MC 1.17/1.18 Terrain/Entity/Inventory (#1943)

Merge branch 'master' of github.com:milutinke/Minecraft-Console-Client into milutinke-master

Manually fix merge conflicts
Additional changes:
 - WindowItems: Fix data type for "elements" below 1.17
 - DestroyEntities: Fix packet palettes and remove DestroyEntity
 - EntityMetadata: Throw exception if health field mapping is not updated

Co-authored-by: Milutinke <bgteam@live.com>
Co-authored-by: BruceChen <MrChen131217@gmail.com>
This commit is contained in:
ORelio 2022-08-19 16:35:55 +02:00
commit 1ce7850193
34 changed files with 5983 additions and 920 deletions

View file

@ -103,11 +103,15 @@ namespace MinecraftClient.ChatBots
}
}
}
// check entity distance and health again
if (shouldAttackEntity(entitiesToAttack[priorityEntity]))
if (entitiesToAttack.ContainsKey(priorityEntity))
{
InteractEntity(priorityEntity, interactMode); // hit the entity!
SendAnimation(Inventory.Hand.MainHand); // Arm animation
// check entity distance and health again
if (shouldAttackEntity(entitiesToAttack[priorityEntity]))
{
InteractEntity(priorityEntity, interactMode); // hit the entity!
SendAnimation(Inventory.Hand.MainHand); // Arm animation
}
}
}
else
@ -143,6 +147,22 @@ namespace MinecraftClient.ChatBots
}
}
public override void OnEntityHealth(Entity entity, float health)
{
if (!entity.Type.IsHostile())
return;
if (entitiesToAttack.ContainsKey(entity.ID))
{
entitiesToAttack[entity.ID].Health = health;
if (entitiesToAttack[entity.ID].Health <= 0)
{
entitiesToAttack.Remove(entity.ID);
}
}
}
public override void OnEntityMove(Entity entity)
{
shouldAttackEntity(entity);

View file

@ -8,7 +8,7 @@ namespace MinecraftClient.Commands
public class Move : Command
{
public override string CmdName { get { return "move"; } }
public override string CmdUsage { get { return "move <on|off|get|up|down|east|west|north|south|x y z|gravity [on|off]> [-f]"; } }
public override string CmdUsage { get { return "move <on|off|get|up|down|east|west|north|south|center|x y z|gravity [on|off]> [-f]"; } }
public override string CmdDesc { get { return "walk or start walking. \"-f\": force unsafe movements like falling or touching fire"; } }
public override string Run(McClient handler, string command, Dictionary<string, object> localVars)
@ -17,7 +17,14 @@ namespace MinecraftClient.Commands
bool takeRisk = false;
if (args.Count < 1)
return GetCmdDescTranslated();
{
string desc = GetCmdDescTranslated();
if (handler.GetTerrainEnabled())
handler.Log.Info(getChunkLoadingStatus(handler.GetWorld()));
return desc;
}
if (args.Contains("-f"))
{
@ -56,6 +63,11 @@ namespace MinecraftClient.Commands
case "west": direction = Direction.West; break;
case "north": direction = Direction.North; break;
case "south": direction = Direction.South; break;
case "center":
Location current = handler.GetCurrentLocation();
Location currentCenter = new Location(Math.Floor(current.X) + 0.5, current.Y, Math.Floor(current.Z) + 0.5);
handler.MoveTo(currentCenter, allowDirectTeleport: true);
return Translations.Get("cmd.move.walk", currentCenter, current);
case "get": return handler.GetCurrentLocation().ToString();
default: return Translations.Get("cmd.look.unknown", args[0]);
}
@ -76,8 +88,15 @@ namespace MinecraftClient.Commands
int z = int.Parse(args[2]);
Location goal = new Location(x, y, z);
if (handler.GetWorld().GetChunkColumn(goal) == null || handler.GetWorld().GetChunkColumn(goal).FullyLoaded == false)
return Translations.Get("cmd.move.chunk_not_loaded");
Location current = handler.GetCurrentLocation();
Location currentCenter = new Location(Math.Floor(current.X) + 0.5, current.Y, Math.Floor(current.Z) + 0.5);
handler.MoveTo(currentCenter, allowDirectTeleport: true);
if (handler.MoveTo(goal, allowUnsafe: takeRisk))
return Translations.Get("cmd.move.walk", goal);
return Translations.Get("cmd.move.walk", goal, current);
else return takeRisk ? Translations.Get("cmd.move.fail", goal) : Translations.Get("cmd.move.suggestforce", goal);
}
catch (FormatException) { return GetCmdDescTranslated(); }
@ -86,5 +105,19 @@ namespace MinecraftClient.Commands
}
else return Translations.Get("extra.terrainandmovement_required");
}
private string getChunkLoadingStatus(World world)
{
double chunkLoadedRatio;
if (world.chunkCnt == 0)
chunkLoadedRatio = 0;
else
chunkLoadedRatio = (world.chunkCnt - world.chunkLoadNotCompleted) / (double)world.chunkCnt;
string status = Translations.Get("cmd.move.chunk_loading_status",
chunkLoadedRatio, world.chunkCnt - world.chunkLoadNotCompleted, world.chunkCnt);
return status;
}
}
}

View file

@ -25,6 +25,11 @@ namespace MinecraftClient.Inventory
/// </summary>
public string Title;
/// <summary>
/// state of container
/// </summary>
public int StateID;
/// <summary>
/// Container Items
/// </summary>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,7 @@ namespace MinecraftClient.Inventory
{
Unknown = -2, // Unsupported item type (Forge mod custom item...)
Null = -1, // Unspecified item type (Used in the network protocol)
AcaciaBoat,
AcaciaButton,
AcaciaDoor,
@ -33,6 +33,9 @@ namespace MinecraftClient.Inventory
ActivatorRail,
Air,
Allium,
AmethystBlock,
AmethystCluster,
AmethystShard,
AncientDebris,
Andesite,
AndesiteSlab,
@ -42,6 +45,10 @@ namespace MinecraftClient.Inventory
Apple,
ArmorStand,
Arrow,
AxolotlBucket,
AxolotlSpawnEgg,
Azalea,
AzaleaLeaves,
AzureBluet,
BakedPotato,
Bamboo,
@ -51,14 +58,15 @@ namespace MinecraftClient.Inventory
BatSpawnEgg,
Beacon,
Bedrock,
Beef,
Beehive,
BeeNest,
BeeSpawnEgg,
Beef,
Beehive,
Beetroot,
BeetrootSeeds,
BeetrootSoup,
Bell,
BigDripleaf,
BirchBoat,
BirchButton,
BirchDoor,
@ -76,6 +84,7 @@ namespace MinecraftClient.Inventory
BirchWood,
BlackBanner,
BlackBed,
BlackCandle,
BlackCarpet,
BlackConcrete,
BlackConcretePowder,
@ -84,18 +93,19 @@ namespace MinecraftClient.Inventory
BlackShulkerBox,
BlackStainedGlass,
BlackStainedGlassPane,
BlackTerracotta,
BlackWool,
Blackstone,
BlackstoneSlab,
BlackstoneStairs,
BlackstoneWall,
BlackTerracotta,
BlackWool,
BlastFurnace,
BlazePowder,
BlazeRod,
BlazeSpawnEgg,
BlueBanner,
BlueBed,
BlueCandle,
BlueCarpet,
BlueConcrete,
BlueConcretePowder,
@ -121,12 +131,13 @@ namespace MinecraftClient.Inventory
Bread,
BrewingStand,
Brick,
Bricks,
BrickSlab,
BrickStairs,
BrickWall,
Bricks,
BrownBanner,
BrownBed,
BrownCandle,
BrownCarpet,
BrownConcrete,
BrownConcretePowder,
@ -143,9 +154,13 @@ namespace MinecraftClient.Inventory
BubbleCoralBlock,
BubbleCoralFan,
Bucket,
BuddingAmethyst,
Bundle,
Cactus,
Cake,
Calcite,
Campfire,
Candle,
Carrot,
CarrotOnAStick,
CartographyTable,
@ -165,6 +180,7 @@ namespace MinecraftClient.Inventory
Chicken,
ChickenSpawnEgg,
ChippedAnvil,
ChiseledDeepslate,
ChiseledNetherBricks,
ChiseledPolishedBlackstone,
ChiseledQuartzBlock,
@ -181,6 +197,10 @@ namespace MinecraftClient.Inventory
CoalBlock,
CoalOre,
CoarseDirt,
CobbledDeepslate,
CobbledDeepslateSlab,
CobbledDeepslateStairs,
CobbledDeepslateWall,
Cobblestone,
CobblestoneSlab,
CobblestoneStairs,
@ -204,8 +224,13 @@ namespace MinecraftClient.Inventory
CookedRabbit,
CookedSalmon,
Cookie,
CopperBlock,
CopperIngot,
CopperOre,
Cornflower,
CowSpawnEgg,
CrackedDeepslateBricks,
CrackedDeepslateTiles,
CrackedNetherBricks,
CrackedPolishedBlackstoneBricks,
CrackedStoneBricks,
@ -230,12 +255,16 @@ namespace MinecraftClient.Inventory
CrimsonTrapdoor,
Crossbow,
CryingObsidian,
CutCopper,
CutCopperSlab,
CutCopperStairs,
CutRedSandstone,
CutRedSandstoneSlab,
CutSandstone,
CutSandstoneSlab,
CyanBanner,
CyanBed,
CyanCandle,
CyanCarpet,
CyanConcrete,
CyanConcretePowder,
@ -284,6 +313,23 @@ namespace MinecraftClient.Inventory
DeadTubeCoralBlock,
DeadTubeCoralFan,
DebugStick,
Deepslate,
DeepslateBrickSlab,
DeepslateBrickStairs,
DeepslateBrickWall,
DeepslateBricks,
DeepslateCoalOre,
DeepslateCopperOre,
DeepslateDiamondOre,
DeepslateEmeraldOre,
DeepslateGoldOre,
DeepslateIronOre,
DeepslateLapisOre,
DeepslateRedstoneOre,
DeepslateTileSlab,
DeepslateTileStairs,
DeepslateTileWall,
DeepslateTiles,
DetectorRail,
Diamond,
DiamondAxe,
@ -311,6 +357,7 @@ namespace MinecraftClient.Inventory
DragonHead,
DriedKelp,
DriedKelpBlock,
DripstoneBlock,
Dropper,
DrownedSpawnEgg,
Egg,
@ -323,20 +370,24 @@ namespace MinecraftClient.Inventory
EnchantedGoldenApple,
EnchantingTable,
EndCrystal,
EnderChest,
EnderEye,
EndermanSpawnEgg,
EndermiteSpawnEgg,
EnderPearl,
EndPortalFrame,
EndRod,
EndStone,
EndStoneBricks,
EndStoneBrickSlab,
EndStoneBrickStairs,
EndStoneBrickWall,
EndStoneBricks,
EnderChest,
EnderEye,
EnderPearl,
EndermanSpawnEgg,
EndermiteSpawnEgg,
EvokerSpawnEgg,
ExperienceBottle,
ExposedCopper,
ExposedCutCopper,
ExposedCutCopperSlab,
ExposedCutCopperStairs,
Farmland,
Feather,
FermentedSpiderEye,
@ -354,6 +405,8 @@ namespace MinecraftClient.Inventory
FlintAndSteel,
FlowerBannerPattern,
FlowerPot,
FloweringAzalea,
FloweringAzaleaLeaves,
FoxSpawnEgg,
Furnace,
FurnaceMinecart,
@ -365,9 +418,18 @@ namespace MinecraftClient.Inventory
GlassPane,
GlisteringMelonSlice,
GlobeBannerPattern,
GlowBerries,
GlowInkSac,
GlowItemFrame,
GlowLichen,
GlowSquidSpawnEgg,
Glowstone,
GlowstoneDust,
GoatSpawnEgg,
GoldBlock,
GoldIngot,
GoldNugget,
GoldOre,
GoldenApple,
GoldenAxe,
GoldenBoots,
@ -380,9 +442,6 @@ namespace MinecraftClient.Inventory
GoldenPickaxe,
GoldenShovel,
GoldenSword,
GoldIngot,
GoldNugget,
GoldOre,
Granite,
GraniteSlab,
GraniteStairs,
@ -393,6 +452,7 @@ namespace MinecraftClient.Inventory
Gravel,
GrayBanner,
GrayBed,
GrayCandle,
GrayCarpet,
GrayConcrete,
GrayConcretePowder,
@ -405,6 +465,7 @@ namespace MinecraftClient.Inventory
GrayWool,
GreenBanner,
GreenBed,
GreenCandle,
GreenCarpet,
GreenConcrete,
GreenConcretePowder,
@ -418,6 +479,7 @@ namespace MinecraftClient.Inventory
Grindstone,
GuardianSpawnEgg,
Gunpowder,
HangingRoots,
HayBlock,
HeartOfTheSea,
HeavyWeightedPressurePlate,
@ -437,6 +499,7 @@ namespace MinecraftClient.Inventory
InfestedChiseledStoneBricks,
InfestedCobblestone,
InfestedCrackedStoneBricks,
InfestedDeepslate,
InfestedMossyStoneBricks,
InfestedStone,
InfestedStoneBricks,
@ -484,6 +547,7 @@ namespace MinecraftClient.Inventory
LapisBlock,
LapisLazuli,
LapisOre,
LargeAmethystBud,
LargeFern,
LavaBucket,
Lead,
@ -495,8 +559,10 @@ namespace MinecraftClient.Inventory
LeatherLeggings,
Lectern,
Lever,
Light,
LightBlueBanner,
LightBlueBed,
LightBlueCandle,
LightBlueCarpet,
LightBlueConcrete,
LightBlueConcretePowder,
@ -509,6 +575,7 @@ namespace MinecraftClient.Inventory
LightBlueWool,
LightGrayBanner,
LightGrayBed,
LightGrayCandle,
LightGrayCarpet,
LightGrayConcrete,
LightGrayConcretePowder,
@ -520,11 +587,13 @@ namespace MinecraftClient.Inventory
LightGrayTerracotta,
LightGrayWool,
LightWeightedPressurePlate,
LightningRod,
Lilac,
LilyOfTheValley,
LilyPad,
LimeBanner,
LimeBed,
LimeCandle,
LimeCarpet,
LimeConcrete,
LimeConcretePowder,
@ -541,6 +610,7 @@ namespace MinecraftClient.Inventory
Loom,
MagentaBanner,
MagentaBed,
MagentaCandle,
MagentaCarpet,
MagentaConcrete,
MagentaConcretePowder,
@ -555,6 +625,7 @@ namespace MinecraftClient.Inventory
MagmaCream,
MagmaCubeSpawnEgg,
Map,
MediumAmethystBud,
Melon,
MelonSeeds,
MelonSlice,
@ -562,14 +633,16 @@ namespace MinecraftClient.Inventory
Minecart,
MojangBannerPattern,
MooshroomSpawnEgg,
MossBlock,
MossCarpet,
MossyCobblestone,
MossyCobblestoneSlab,
MossyCobblestoneStairs,
MossyCobblestoneWall,
MossyStoneBricks,
MossyStoneBrickSlab,
MossyStoneBrickStairs,
MossyStoneBrickWall,
MossyStoneBricks,
MuleSpawnEgg,
MushroomStem,
MushroomStew,
@ -581,6 +654,7 @@ namespace MinecraftClient.Inventory
MusicDiscFar,
MusicDiscMall,
MusicDiscMellohi,
MusicDiscOtherside,
MusicDiscPigstep,
MusicDiscStal,
MusicDiscStrad,
@ -592,11 +666,16 @@ namespace MinecraftClient.Inventory
NautilusShell,
NetherBrick,
NetherBrickFence,
NetherBricks,
NetherBrickSlab,
NetherBrickStairs,
NetherBrickWall,
NetherBricks,
NetherGoldOre,
NetherQuartzOre,
NetherSprouts,
NetherStar,
NetherWart,
NetherWartBlock,
NetheriteAxe,
NetheriteBlock,
NetheriteBoots,
@ -609,12 +688,7 @@ namespace MinecraftClient.Inventory
NetheriteScrap,
NetheriteShovel,
NetheriteSword,
NetherQuartzOre,
Netherrack,
NetherSprouts,
NetherStar,
NetherWart,
NetherWartBlock,
NoteBlock,
OakBoat,
OakButton,
@ -636,6 +710,7 @@ namespace MinecraftClient.Inventory
OcelotSpawnEgg,
OrangeBanner,
OrangeBed,
OrangeCandle,
OrangeCarpet,
OrangeConcrete,
OrangeConcretePowder,
@ -648,6 +723,10 @@ namespace MinecraftClient.Inventory
OrangeTulip,
OrangeWool,
OxeyeDaisy,
OxidizedCopper,
OxidizedCutCopper,
OxidizedCutCopperSlab,
OxidizedCutCopperStairs,
PackedIce,
Painting,
PandaSpawnEgg,
@ -657,13 +736,14 @@ namespace MinecraftClient.Inventory
PetrifiedOakSlab,
PhantomMembrane,
PhantomSpawnEgg,
PigSpawnEgg,
PiglinBannerPattern,
PiglinBruteSpawnEgg,
PiglinSpawnEgg,
PigSpawnEgg,
PillagerSpawnEgg,
PinkBanner,
PinkBed,
PinkCandle,
PinkCarpet,
PinkConcrete,
PinkConcretePowder,
@ -678,6 +758,7 @@ namespace MinecraftClient.Inventory
Piston,
PlayerHead,
Podzol,
PointedDripstone,
PoisonousPotato,
PolarBearSpawnEgg,
PolishedAndesite,
@ -685,15 +766,19 @@ namespace MinecraftClient.Inventory
PolishedAndesiteStairs,
PolishedBasalt,
PolishedBlackstone,
PolishedBlackstoneBricks,
PolishedBlackstoneBrickSlab,
PolishedBlackstoneBrickStairs,
PolishedBlackstoneBrickWall,
PolishedBlackstoneBricks,
PolishedBlackstoneButton,
PolishedBlackstonePressurePlate,
PolishedBlackstoneSlab,
PolishedBlackstoneStairs,
PolishedBlackstoneWall,
PolishedDeepslate,
PolishedDeepslateSlab,
PolishedDeepslateStairs,
PolishedDeepslateWall,
PolishedDiorite,
PolishedDioriteSlab,
PolishedDioriteStairs,
@ -705,11 +790,12 @@ namespace MinecraftClient.Inventory
Porkchop,
Potato,
Potion,
PowderSnowBucket,
PoweredRail,
Prismarine,
PrismarineBricks,
PrismarineBrickSlab,
PrismarineBrickStairs,
PrismarineBricks,
PrismarineCrystals,
PrismarineShard,
PrismarineSlab,
@ -723,6 +809,7 @@ namespace MinecraftClient.Inventory
PumpkinSeeds,
PurpleBanner,
PurpleBed,
PurpleCandle,
PurpleCarpet,
PurpleConcrete,
PurpleConcretePowder,
@ -750,8 +837,15 @@ namespace MinecraftClient.Inventory
RabbitStew,
Rail,
RavagerSpawnEgg,
RawCopper,
RawCopperBlock,
RawGold,
RawGoldBlock,
RawIron,
RawIronBlock,
RedBanner,
RedBed,
RedCandle,
RedCarpet,
RedConcrete,
RedConcretePowder,
@ -759,10 +853,10 @@ namespace MinecraftClient.Inventory
RedGlazedTerracotta,
RedMushroom,
RedMushroomBlock,
RedNetherBricks,
RedNetherBrickSlab,
RedNetherBrickStairs,
RedNetherBrickWall,
RedNetherBricks,
RedSand,
RedSandstone,
RedSandstoneSlab,
@ -771,17 +865,18 @@ namespace MinecraftClient.Inventory
RedShulkerBox,
RedStainedGlass,
RedStainedGlassPane,
RedTerracotta,
RedTulip,
RedWool,
Redstone,
RedstoneBlock,
RedstoneLamp,
RedstoneOre,
RedstoneTorch,
RedTerracotta,
RedTulip,
RedWool,
Repeater,
RepeatingCommandBlock,
RespawnAnchor,
RootedDirt,
RoseBush,
RottenFlesh,
Saddle,
@ -794,10 +889,11 @@ namespace MinecraftClient.Inventory
SandstoneStairs,
SandstoneWall,
Scaffolding,
SculkSensor,
Scute,
Seagrass,
SeaLantern,
SeaPickle,
Seagrass,
Shears,
SheepSpawnEgg,
Shield,
@ -813,8 +909,11 @@ namespace MinecraftClient.Inventory
SlimeBall,
SlimeBlock,
SlimeSpawnEgg,
SmallAmethystBud,
SmallDripleaf,
SmithingTable,
Smoker,
SmoothBasalt,
SmoothQuartz,
SmoothQuartzSlab,
SmoothQuartzStairs,
@ -827,8 +926,8 @@ namespace MinecraftClient.Inventory
SmoothStone,
SmoothStoneSlab,
Snow,
Snowball,
SnowBlock,
Snowball,
SoulCampfire,
SoulLantern,
SoulSand,
@ -840,6 +939,7 @@ namespace MinecraftClient.Inventory
SpiderSpawnEgg,
SplashPotion,
Sponge,
SporeBlossom,
SpruceBoat,
SpruceButton,
SpruceDoor,
@ -855,17 +955,17 @@ namespace MinecraftClient.Inventory
SpruceStairs,
SpruceTrapdoor,
SpruceWood,
Spyglass,
SquidSpawnEgg,
Stick,
StickyPiston,
Stone,
StoneAxe,
StoneBricks,
StoneBrickSlab,
StoneBrickStairs,
StoneBrickWall,
StoneBricks,
StoneButton,
Stonecutter,
StoneHoe,
StonePickaxe,
StonePressurePlate,
@ -873,6 +973,7 @@ namespace MinecraftClient.Inventory
StoneSlab,
StoneStairs,
StoneSword,
Stonecutter,
StraySpawnEgg,
StriderSpawnEgg,
String,
@ -902,6 +1003,7 @@ namespace MinecraftClient.Inventory
TallGrass,
Target,
Terracotta,
TintedGlass,
TippedArrow,
Tnt,
TntMinecart,
@ -917,6 +1019,7 @@ namespace MinecraftClient.Inventory
TubeCoral,
TubeCoralBlock,
TubeCoralFan,
Tuff,
TurtleEgg,
TurtleHelmet,
TurtleSpawnEgg,
@ -944,12 +1047,33 @@ namespace MinecraftClient.Inventory
WarpedTrapdoor,
WarpedWartBlock,
WaterBucket,
WaxedCopperBlock,
WaxedCutCopper,
WaxedCutCopperSlab,
WaxedCutCopperStairs,
WaxedExposedCopper,
WaxedExposedCutCopper,
WaxedExposedCutCopperSlab,
WaxedExposedCutCopperStairs,
WaxedOxidizedCopper,
WaxedOxidizedCutCopper,
WaxedOxidizedCutCopperSlab,
WaxedOxidizedCutCopperStairs,
WaxedWeatheredCopper,
WaxedWeatheredCutCopper,
WaxedWeatheredCutCopperSlab,
WaxedWeatheredCutCopperStairs,
WeatheredCopper,
WeatheredCutCopper,
WeatheredCutCopperSlab,
WeatheredCutCopperStairs,
WeepingVines,
WetSponge,
Wheat,
WheatSeeds,
WhiteBanner,
WhiteBed,
WhiteCandle,
WhiteCarpet,
WhiteConcrete,
WhiteConcretePowder,
@ -975,6 +1099,7 @@ namespace MinecraftClient.Inventory
WrittenBook,
YellowBanner,
YellowBed,
YellowCandle,
YellowCarpet,
YellowConcrete,
YellowConcretePowder,

View file

@ -50,11 +50,13 @@ namespace MinecraftClient.Inventory
ItemType[] t =
{
ItemType.AcaciaBoat,
ItemType.AxolotlBucket,
ItemType.BirchBoat,
ItemType.BlackBed,
ItemType.BlackShulkerBox,
ItemType.BlueBed,
ItemType.BlueShulkerBox,
ItemType.Bundle,
ItemType.Bow,
ItemType.BrownBed,
ItemType.BrownShulkerBox,
@ -142,6 +144,7 @@ namespace MinecraftClient.Inventory
ItemType.MusicDiscFar,
ItemType.MusicDiscMall,
ItemType.MusicDiscMellohi,
ItemType.MusicDiscOtherside,
ItemType.MusicDiscStal,
ItemType.MusicDiscStrad,
ItemType.MusicDiscWait,
@ -152,6 +155,7 @@ namespace MinecraftClient.Inventory
ItemType.PinkBed,
ItemType.PinkShulkerBox,
ItemType.Potion,
ItemType.PowderSnowBucket,
ItemType.PufferfishBucket,
ItemType.PurpleBed,
ItemType.PurpleShulkerBox,
@ -166,6 +170,7 @@ namespace MinecraftClient.Inventory
ItemType.SkullBannerPattern,
ItemType.SplashPotion,
ItemType.SpruceBoat,
ItemType.Spyglass,
ItemType.StoneAxe,
ItemType.StoneHoe,
ItemType.StonePickaxe,

View file

@ -23,6 +23,17 @@ namespace MinecraftClient.Mapping.BlockPalettes
/// </remarks>
public static class BlockPaletteGenerator
{
/// <summary>
/// Generate mapping from Minecraft blocks.json
/// </summary>
/// <param name="blocksJsonFile">path to blocks.json</param>
/// <remarks>java -cp minecraft_server.jar net.minecraft.data.Main --reports</remarks>
/// <returns>state => block name mappings</returns>
public static void GenerateBlockPalette(string blocksJsonFile)
{
BlockPaletteGenerator.JsonToClass(blocksJsonFile, "Palette", "Material");
}
/// <summary>
/// Generate mapping from Minecraft blocks.json
/// </summary>
@ -33,6 +44,9 @@ namespace MinecraftClient.Mapping.BlockPalettes
/// <returns>state => block name mappings</returns>
public static void JsonToClass(string blocksJsonFile, string outputClass, string outputEnum = null)
{
string outputPalettePath = Path.Combine(Path.GetDirectoryName(blocksJsonFile), outputClass + "XXX.cs");
string outputEnumPath = Path.Combine(Path.GetDirectoryName(blocksJsonFile), outputEnum + "XXX.cs");
HashSet<int> knownStates = new HashSet<int>();
Dictionary<string, HashSet<int>> blocks = new Dictionary<string, HashSet<int>>();
@ -70,7 +84,7 @@ namespace MinecraftClient.Mapping.BlockPalettes
"",
"namespace MinecraftClient.Mapping.BlockPalettes",
"{",
" public class PaletteXXX : PaletteMapping",
" public class PaletteXXX : BlockPalette",
" {",
" private static Dictionary<int, Material> materials = new Dictionary<int, Material>();",
"",
@ -121,7 +135,7 @@ namespace MinecraftClient.Mapping.BlockPalettes
"}"
});
File.WriteAllLines(outputClass, outFile);
File.WriteAllLines(outputPalettePath, outFile);
if (outputEnum != null)
{
@ -138,7 +152,7 @@ namespace MinecraftClient.Mapping.BlockPalettes
" }",
"}"
});
File.WriteAllLines(outputEnum, outFile);
File.WriteAllLines(outputEnumPath, outFile);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -11,18 +11,29 @@ namespace MinecraftClient.Mapping
/// </summary>
public class ChunkColumn
{
public const int ColumnSize = 16;
public int ColumnSize;
public bool FullyLoaded = false;
/// <summary>
/// Blocks contained into the chunk
/// </summary>
private readonly Chunk[] chunks = new Chunk[ColumnSize];
private readonly Chunk[] chunks;
/// <summary>
/// Lock for thread safety
/// </summary>
private readonly ReaderWriterLockSlim chunkLock = new ReaderWriterLockSlim();
/// <summary>
/// Create a new ChunkColumn
/// </summary>
public ChunkColumn(int size = 16)
{
ColumnSize = size;
chunks = new Chunk[size];
}
/// <summary>
/// Get or set the specified chunk column
/// </summary>

View file

@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MinecraftClient.Mapping
{
/// <summary>
/// The dimension type, available after 1.16.2
/// </summary>
public class Dimension
{
/// <summary>
/// The name of the dimension type (for example, "minecraft:overworld").
/// </summary>
public readonly string Name;
/// <summary>
/// Whether piglins shake and transform to zombified piglins.
/// </summary>
public readonly bool piglinSafe = false;
/// <summary>
/// When false, compasses spin randomly. When true, nether portals can spawn zombified piglins.
/// </summary>
public readonly bool natural = true;
/// <summary>
/// How much light the dimension has.
/// </summary>
public readonly float ambientLight = 0.0f;
/// <summary>
/// If set, the time of the day is the specified value.
/// Value: -1: not set
/// Value: [0, 24000]: time of the day
/// </summary>
public readonly long fixedTime = -1;
/// <summary>
/// A resource location defining what block tag to use for infiniburn.
/// Value above 1.18.2: "#" or minecraft resource "#minecraft:...".
/// Value below 1.18.1: "" or minecraft resource "minecraft:...".
/// </summary>
public readonly string infiniburn = "#minecraft:infiniburn_overworld";
/// <summary>
/// Whether players can charge and use respawn anchors.
/// </summary>
public readonly bool respawnAnchorWorks = false;
/// <summary>
/// Whether the dimension has skylight access or not.
/// </summary>
public readonly bool hasSkylight = true;
/// <summary>
/// Whether players can use a bed to sleep.
/// </summary>
public readonly bool bedWorks = true;
/// <summary>
/// unknown
/// Values: "minecraft:overworld", "minecraft:the_nether", "minecraft:the_end" or something else.
/// </summary>
public readonly string effects = "minecraft:overworld";
/// <summary>
/// Whether players with the Bad Omen effect can cause a raid.
/// </summary>
public readonly bool hasRaids = true;
/// <summary>
/// The minimum Y level.
/// </summary>
public readonly int minY = 0;
/// <summary>
/// The maximum Y level.
/// </summary>
public readonly int maxY = 256;
/// <summary>
/// The maximum height.
/// </summary>
public readonly int height = 256;
/// <summary>
/// The maximum height to which chorus fruits and nether portals can bring players within this dimension.
/// </summary>
public readonly int logicalHeight = 256;
/// <summary>
/// The multiplier applied to coordinates when traveling to the dimension.
/// </summary>
public readonly double coordinateScale = 1.0;
/// <summary>
/// Whether the dimensions behaves like the nether (water evaporates and sponges dry) or not. Also causes lava to spread thinner.
/// </summary>
public readonly bool ultrawarm = false;
/// <summary>
/// Whether the dimension has a bedrock ceiling or not. When true, causes lava to spread faster.
/// </summary>
public readonly bool hasCeiling = false;
/// <summary>
/// Default value used in version below 1.17
/// </summary>
public Dimension()
{
this.Name = "minecraft:overworld";
}
/// <summary>
/// Create from the "Dimension Codec" NBT Tag Compound
/// </summary>
/// <param name="name">Dimension name</param>
/// <param name="nbt">The dimension type (NBT Tag Compound)</param>
public Dimension(string name, Dictionary<string, object> nbt)
{
if (name == null)
throw new ArgumentNullException("name");
if (nbt == null)
throw new ArgumentNullException("nbt Data");
this.Name = name;
if (nbt.ContainsKey("piglin_safe"))
this.piglinSafe = 1 == (byte)nbt["piglin_safe"];
if (nbt.ContainsKey("natural"))
this.natural = 1 == (byte)nbt["natural"];
if (nbt.ContainsKey("ambient_light"))
this.ambientLight = (float)nbt["ambient_light"];
if (nbt.ContainsKey("fixed_time"))
this.fixedTime = (long)nbt["fixed_time"];
if (nbt.ContainsKey("infiniburn"))
this.infiniburn = (string)nbt["infiniburn"];
if (nbt.ContainsKey("respawn_anchor_works"))
this.respawnAnchorWorks = 1 == (byte)nbt["respawn_anchor_works"];
if (nbt.ContainsKey("has_skylight"))
this.hasSkylight = 1 == (byte)nbt["has_skylight"];
if (nbt.ContainsKey("bed_works"))
this.bedWorks = 1 == (byte)nbt["bed_works"];
if (nbt.ContainsKey("effects"))
this.effects = (string)nbt["effects"];
if (nbt.ContainsKey("has_raids"))
this.hasRaids = 1 == (byte)nbt["has_raids"];
if (nbt.ContainsKey("min_y"))
this.minY = (int)nbt["min_y"];
if (nbt.ContainsKey("height"))
this.height = (int)nbt["height"];
if (nbt.ContainsKey("min_y") && nbt.ContainsKey("height"))
this.maxY = this.minY + this.height;
if (nbt.ContainsKey("logical_height"))
this.logicalHeight = (int)nbt["logical_height"];
if (nbt.ContainsKey("coordinate_scale"))
{
var coordinateScaleObj = nbt["coordinate_scale"];
if (coordinateScaleObj.GetType() == typeof(float))
this.coordinateScale = (float)coordinateScaleObj;
else
this.coordinateScale = (double)coordinateScaleObj;
}
if (nbt.ContainsKey("ultrawarm"))
this.ultrawarm = 1 == (byte)nbt["ultrawarm"];
if (nbt.ContainsKey("has_ceiling"))
this.hasCeiling = 1 == (byte)nbt["has_ceiling"];
}
}
}

View file

@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
namespace MinecraftClient.Mapping.EntityPalettes
{
public class EntityPalette117 : EntityPalette
{
private static Dictionary<int, EntityType> mappings = new Dictionary<int, EntityType>();
static EntityPalette117()
{
mappings[0] = EntityType.AreaEffectCloud;
mappings[1] = EntityType.ArmorStand;
mappings[2] = EntityType.Arrow;
mappings[3] = EntityType.Axolotl;
mappings[4] = EntityType.Bat;
mappings[5] = EntityType.Bee;
mappings[6] = EntityType.Blaze;
mappings[7] = EntityType.Boat;
mappings[8] = EntityType.Cat;
mappings[9] = EntityType.CaveSpider;
mappings[10] = EntityType.Chicken;
mappings[11] = EntityType.Cod;
mappings[12] = EntityType.Cow;
mappings[13] = EntityType.Creeper;
mappings[14] = EntityType.Dolphin;
mappings[15] = EntityType.Donkey;
mappings[16] = EntityType.DragonFireball;
mappings[17] = EntityType.Drowned;
mappings[18] = EntityType.ElderGuardian;
mappings[19] = EntityType.EndCrystal;
mappings[20] = EntityType.EnderDragon;
mappings[21] = EntityType.Enderman;
mappings[22] = EntityType.Endermite;
mappings[23] = EntityType.Evoker;
mappings[24] = EntityType.EvokerFangs;
mappings[25] = EntityType.ExperienceOrb;
mappings[26] = EntityType.EyeOfEnder;
mappings[27] = EntityType.FallingBlock;
mappings[28] = EntityType.FireworkRocket;
mappings[29] = EntityType.Fox;
mappings[30] = EntityType.Ghast;
mappings[31] = EntityType.Giant;
mappings[32] = EntityType.GlowItemFrame;
mappings[33] = EntityType.GlowSquid;
mappings[34] = EntityType.Goat;
mappings[35] = EntityType.Guardian;
mappings[36] = EntityType.Hoglin;
mappings[37] = EntityType.Horse;
mappings[38] = EntityType.Husk;
mappings[39] = EntityType.Illusioner;
mappings[40] = EntityType.IronGolem;
mappings[41] = EntityType.Item;
mappings[42] = EntityType.ItemFrame;
mappings[43] = EntityType.Fireball;
mappings[44] = EntityType.LeashKnot;
mappings[45] = EntityType.LightningBolt;
mappings[46] = EntityType.Llama;
mappings[47] = EntityType.LlamaSpit;
mappings[48] = EntityType.MagmaCube;
mappings[49] = EntityType.Marker;
mappings[50] = EntityType.Minecart;
mappings[51] = EntityType.ChestMinecart;
mappings[52] = EntityType.CommandBlockMinecart;
mappings[53] = EntityType.FurnaceMinecart;
mappings[54] = EntityType.HopperMinecart;
mappings[55] = EntityType.SpawnerMinecart;
mappings[56] = EntityType.TntMinecart;
mappings[57] = EntityType.Mule;
mappings[58] = EntityType.Mooshroom;
mappings[59] = EntityType.Ocelot;
mappings[60] = EntityType.Painting;
mappings[61] = EntityType.Panda;
mappings[62] = EntityType.Parrot;
mappings[63] = EntityType.Phantom;
mappings[64] = EntityType.Pig;
mappings[65] = EntityType.Piglin;
mappings[66] = EntityType.PiglinBrute;
mappings[67] = EntityType.Pillager;
mappings[68] = EntityType.PolarBear;
mappings[69] = EntityType.Tnt;
mappings[70] = EntityType.Pufferfish;
mappings[71] = EntityType.Rabbit;
mappings[72] = EntityType.Ravager;
mappings[73] = EntityType.Salmon;
mappings[74] = EntityType.Sheep;
mappings[75] = EntityType.Shulker;
mappings[76] = EntityType.ShulkerBullet;
mappings[77] = EntityType.Silverfish;
mappings[78] = EntityType.Skeleton;
mappings[79] = EntityType.SkeletonHorse;
mappings[80] = EntityType.Slime;
mappings[81] = EntityType.SmallFireball;
mappings[82] = EntityType.SnowGolem;
mappings[83] = EntityType.Snowball;
mappings[84] = EntityType.SpectralArrow;
mappings[85] = EntityType.Spider;
mappings[86] = EntityType.Squid;
mappings[87] = EntityType.Stray;
mappings[88] = EntityType.Strider;
mappings[89] = EntityType.Egg;
mappings[90] = EntityType.EnderPearl;
mappings[91] = EntityType.ExperienceBottle;
mappings[92] = EntityType.Potion;
mappings[93] = EntityType.Trident;
mappings[94] = EntityType.TraderLlama;
mappings[95] = EntityType.TropicalFish;
mappings[96] = EntityType.Turtle;
mappings[97] = EntityType.Vex;
mappings[98] = EntityType.Villager;
mappings[99] = EntityType.Vindicator;
mappings[100] = EntityType.WanderingTrader;
mappings[101] = EntityType.Witch;
mappings[102] = EntityType.Wither;
mappings[103] = EntityType.WitherSkeleton;
mappings[104] = EntityType.WitherSkull;
mappings[105] = EntityType.Wolf;
mappings[106] = EntityType.Zoglin;
mappings[107] = EntityType.Zombie;
mappings[108] = EntityType.ZombieHorse;
mappings[109] = EntityType.ZombieVillager;
mappings[110] = EntityType.ZombifiedPiglin;
mappings[111] = EntityType.Player;
mappings[112] = EntityType.FishingBobber;
}
protected override Dictionary<int, EntityType> GetDict()
{
return mappings;
}
}
}

View file

@ -17,6 +17,7 @@ namespace MinecraftClient.Mapping
AreaEffectCloud,
ArmorStand,
Arrow,
Axolotl,
Bat,
Bee,
Blaze,
@ -53,6 +54,9 @@ namespace MinecraftClient.Mapping
FurnaceMinecart,
Ghast,
Giant,
GlowItemFrame,
GlowSquid,
Goat,
Guardian,
Hoglin,
HopperMinecart,
@ -67,6 +71,7 @@ namespace MinecraftClient.Mapping
Llama,
LlamaSpit,
MagmaCube,
Marker,
Minecart,
Mooshroom,
Mule,

View file

@ -62,6 +62,7 @@ namespace MinecraftClient.Mapping
{
switch (e)
{
case EntityType.GlowItemFrame:
case EntityType.Item:
case EntityType.ItemFrame:
case EntityType.EyeOfEnder:

View file

@ -14,7 +14,7 @@ namespace MinecraftClient.Mapping
/// The X Coordinate
/// </summary>
public double X;
/// <summary>
/// The Y Coordinate (vertical)
/// </summary>
@ -79,7 +79,7 @@ namespace MinecraftClient.Mapping
{
get
{
return (int)Math.Floor(Y / Chunk.SizeY);
return (int)Math.Floor((Y - World.GetDimension().minY) / Chunk.SizeY);
}
}
@ -299,7 +299,7 @@ namespace MinecraftClient.Mapping
/// <returns>String representation of the location</returns>
public override string ToString()
{
return String.Format("X:{0} Y:{1} Z:{2}", X, Y, Z);
return String.Format("X:{0:0.00} Y:{1:0.00} Z:{2:0.00}", X, Y, Z);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -42,9 +42,11 @@ namespace MinecraftClient.Mapping
Material.BrownGlazedTerracotta,
Material.BrownShulkerBox,
Material.BrownTerracotta,
Material.Calcite,
Material.Cauldron,
Material.Chain,
Material.ChippedAnvil,
Material.ChiseledDeepslate,
Material.ChiseledNetherBricks,
Material.ChiseledPolishedBlackstone,
Material.ChiseledQuartzBlock,
@ -53,11 +55,17 @@ namespace MinecraftClient.Mapping
Material.ChiseledStoneBricks,
Material.CoalBlock,
Material.CoalOre,
Material.CobbledDeepslate,
Material.CobbledDeepslateSlab,
Material.CobbledDeepslateStairs,
Material.CobbledDeepslateWall,
Material.Cobblestone,
Material.CobblestoneSlab,
Material.CobblestoneStairs,
Material.CobblestoneWall,
Material.Conduit,
Material.CrackedDeepslateBricks,
Material.CrackedDeepslateTiles,
Material.CrackedNetherBricks,
Material.CrackedPolishedBlackstoneBricks,
Material.CrackedStoneBricks,
@ -74,12 +82,23 @@ namespace MinecraftClient.Mapping
Material.DarkPrismarine,
Material.DarkPrismarineSlab,
Material.DarkPrismarineStairs,
Material.Deepslate,
Material.DeepslateBrickSlab,
Material.DeepslateBrickStairs,
Material.DeepslateBrickWall,
Material.DeepslateBricks,
Material.DeepslateCoalOre,
Material.DeepslateTileSlab,
Material.DeepslateTileStairs,
Material.DeepslateTileWall,
Material.DeepslateTiles,
Material.DetectorRail,
Material.Diorite,
Material.DioriteSlab,
Material.DioriteStairs,
Material.DioriteWall,
Material.Dispenser,
Material.DripstoneBlock,
Material.Dropper,
Material.EnchantingTable,
Material.EndRod,
@ -113,6 +132,7 @@ namespace MinecraftClient.Mapping
Material.IronDoor,
Material.IronTrapdoor,
Material.Lantern,
Material.LavaCauldron,
Material.LightBlueConcrete,
Material.LightBlueGlazedTerracotta,
Material.LightBlueShulkerBox,
@ -160,6 +180,7 @@ namespace MinecraftClient.Mapping
Material.PinkShulkerBox,
Material.PinkTerracotta,
Material.Piston,
Material.PointedDripstone,
Material.PolishedAndesite,
Material.PolishedAndesiteSlab,
Material.PolishedAndesiteStairs,
@ -180,6 +201,7 @@ namespace MinecraftClient.Mapping
Material.PolishedGranite,
Material.PolishedGraniteSlab,
Material.PolishedGraniteStairs,
Material.PowderSnowCauldron,
Material.PoweredRail,
Material.Prismarine,
Material.PrismarineBrickSlab,
@ -221,6 +243,7 @@ namespace MinecraftClient.Mapping
Material.SandstoneWall,
Material.ShulkerBox,
Material.Smoker,
Material.SmoothBasalt,
Material.SmoothQuartz,
Material.SmoothQuartzSlab,
Material.SmoothQuartzStairs,
@ -245,7 +268,9 @@ namespace MinecraftClient.Mapping
Material.StoneStairs,
Material.Stonecutter,
Material.Terracotta,
Material.Tuff,
Material.WarpedNylium,
Material.WaterCauldron,
Material.WhiteConcrete,
Material.WhiteGlazedTerracotta,
Material.WhiteShulkerBox,
@ -253,26 +278,70 @@ namespace MinecraftClient.Mapping
Material.YellowConcrete,
Material.YellowGlazedTerracotta,
Material.YellowShulkerBox,
Material.YellowTerracotta
Material.YellowTerracotta,
};
// Minable by Stone, iron, diamond, netherite.
private static readonly List<Material> pickaxeTier1 = new List<Material>()
{
Material.CopperOre,
Material.CopperBlock,
Material.CutCopperSlab,
Material.CutCopperStairs,
Material.CutCopper,
Material.DeepslateCopperOre,
Material.DeepslateIronOre,
Material.DeepslateLapisOre,
Material.ExposedCopper,
Material.ExposedCutCopperSlab,
Material.ExposedCutCopperStairs,
Material.ExposedCutCopper,
Material.IronBlock,
Material.IronOre,
Material.LapisBlock,
Material.LapisOre,
Material.LightningRod,
Material.OxidizedCopper,
Material.OxidizedCutCopperSlab,
Material.OxidizedCutCopperStairs,
Material.OxidizedCutCopper,
Material.RawCopperBlock,
Material.RawIronBlock,
Material.Terracotta,
Material.WaxedCopperBlock,
Material.WaxedCutCopperSlab,
Material.WaxedCutCopperStairs,
Material.WaxedCutCopper,
Material.WaxedExposedCopper,
Material.WaxedExposedCutCopperSlab,
Material.WaxedExposedCutCopperStairs,
Material.WaxedExposedCutCopper,
Material.WaxedOxidizedCopper,
Material.WaxedOxidizedCutCopperSlab,
Material.WaxedOxidizedCutCopperStairs,
Material.WaxedOxidizedCutCopper,
Material.WaxedWeatheredCopper,
Material.WaxedWeatheredCutCopperSlab,
Material.WaxedWeatheredCutCopperStairs,
Material.WaxedWeatheredCutCopper,
Material.WeatheredCopper,
Material.WeatheredCutCopperSlab,
Material.WeatheredCutCopperStairs,
Material.WeatheredCutCopper,
};
// Minable by Iron, diamond, netherite.
private static readonly List<Material> pickaxeTier2 = new List<Material>()
{
Material.DeepslateDiamondOre,
Material.DeepslateEmeraldOre,
Material.DeepslateGoldOre,
Material.DeepslateRedstoneOre,
Material.DiamondBlock,
Material.DiamondOre,
Material.EmeraldBlock,
Material.EmeraldOre,
Material.GoldBlock,
Material.GoldOre,
Material.RawGoldBlock,
Material.RedstoneOre,
};
// Minable by Diamond, Netherite.
@ -314,13 +383,14 @@ namespace MinecraftClient.Mapping
Material.PurpleConcretePowder,
Material.RedConcretePowder,
Material.RedSand,
Material.RootedDirt,
Material.Sand,
Material.Snow,
Material.SnowBlock,
Material.SoulSand,
Material.SoulSoil,
Material.WhiteConcretePowder,
Material.YellowConcretePowder
Material.YellowConcretePowder,
};
// Every axe can mine every block (speed difference).
private static readonly List<Material> axe = new List<Material>()
@ -341,6 +411,7 @@ namespace MinecraftClient.Mapping
Material.Barrel,
Material.BeeNest,
Material.Beehive,
Material.BigDripleaf,
Material.BirchButton,
Material.BirchDoor,
Material.BirchFence,
@ -504,12 +575,13 @@ namespace MinecraftClient.Mapping
Material.WhiteBanner,
Material.WhiteWallBanner,
Material.YellowBanner,
Material.YellowWallBanner
Material.YellowWallBanner,
};
// Every block a shear can mine.
private static readonly List<Material> shears = new List<Material>()
{
Material.AcaciaLeaves,
Material.AzaleaLeaves,
Material.BirchLeaves,
Material.BlackWool,
Material.BlueWool,
@ -517,6 +589,7 @@ namespace MinecraftClient.Mapping
Material.Cobweb,
Material.CyanWool,
Material.DarkOakLeaves,
Material.FloweringAzaleaLeaves,
Material.GrayWool,
Material.GreenWool,
Material.JungleLeaves,
@ -539,6 +612,7 @@ namespace MinecraftClient.Mapping
Material.Bamboo,
Material.Cobweb,
Material.InfestedChiseledStoneBricks,
Material.InfestedDeepslate,
Material.InfestedCobblestone,
Material.InfestedCrackedStoneBricks,
Material.InfestedMossyStoneBricks,
@ -553,8 +627,10 @@ namespace MinecraftClient.Mapping
Material.DarkOakLeaves,
Material.HayBlock,
Material.JungleLeaves,
Material.MossBlock,
Material.NetherWartBlock,
Material.OakLeaves,
Material.SculkSensor,
Material.Shroomlight,
Material.Sponge,
Material.SpruceLeaves,
@ -565,7 +641,7 @@ namespace MinecraftClient.Mapping
// Liquids
private static readonly List<Material> bucket = new List<Material>()
{
Material.Lava,
Material.Lava,
Material.Water
};
@ -597,7 +673,7 @@ namespace MinecraftClient.Mapping
{
if (pickaxeTier0.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.NetheritePickaxe,
ItemType.DiamondPickaxe,
@ -609,7 +685,7 @@ namespace MinecraftClient.Mapping
}
else if (pickaxeTier1.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.NetheritePickaxe,
ItemType.DiamondPickaxe,
@ -620,7 +696,7 @@ namespace MinecraftClient.Mapping
}
else if (pickaxeTier2.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.NetheritePickaxe,
ItemType.DiamondPickaxe,
@ -629,7 +705,7 @@ namespace MinecraftClient.Mapping
}
else if (pickaxeTier3.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.NetheritePickaxe,
ItemType.DiamondPickaxe,
@ -637,7 +713,7 @@ namespace MinecraftClient.Mapping
}
else if (shovel.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.NetheriteShovel,
ItemType.DiamondShovel,
@ -649,7 +725,7 @@ namespace MinecraftClient.Mapping
}
else if (axe.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.NetheriteAxe,
ItemType.DiamondAxe,
@ -661,14 +737,14 @@ namespace MinecraftClient.Mapping
}
else if (shears.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.Shears,
};
}
else if (sword.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.NetheriteSword,
ItemType.DiamondSword,
@ -680,7 +756,7 @@ namespace MinecraftClient.Mapping
}
else if (hoe.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.NetheriteHoe,
ItemType.DiamondHoe,
@ -692,7 +768,7 @@ namespace MinecraftClient.Mapping
}
else if (bucket.Contains(block))
{
return new ItemType[]
return new ItemType[]
{
ItemType.Bucket,
};

View file

@ -74,6 +74,8 @@ namespace MinecraftClient.Mapping
case Material.JungleLeaves:
case Material.AcaciaLeaves:
case Material.DarkOakLeaves:
case Material.AzaleaLeaves:
case Material.FloweringAzaleaLeaves:
case Material.Sponge:
case Material.WetSponge:
case Material.Glass:
@ -202,6 +204,9 @@ namespace MinecraftClient.Mapping
case Material.EnchantingTable:
case Material.BrewingStand:
case Material.Cauldron:
case Material.WaterCauldron:
case Material.LavaCauldron:
case Material.PowderSnowCauldron:
case Material.EndPortalFrame:
case Material.EndStone:
case Material.DragonEgg:
@ -518,6 +523,119 @@ namespace MinecraftClient.Mapping
case Material.Beehive:
case Material.HoneyBlock:
case Material.HoneycombBlock:
case Material.Candle:
case Material.WhiteCandle:
case Material.OrangeCandle:
case Material.MagentaCandle:
case Material.LightBlueCandle:
case Material.YellowCandle:
case Material.LimeCandle:
case Material.PinkCandle:
case Material.GrayCandle:
case Material.LightGrayCandle:
case Material.CyanCandle:
case Material.PurpleCandle:
case Material.BlueCandle:
case Material.BrownCandle:
case Material.GreenCandle:
case Material.RedCandle:
case Material.BlackCandle:
case Material.CandleCake:
case Material.WhiteCandleCake:
case Material.OrangeCandleCake:
case Material.MagentaCandleCake:
case Material.LightBlueCandleCake:
case Material.YellowCandleCake:
case Material.LimeCandleCake:
case Material.PinkCandleCake:
case Material.GrayCandleCake:
case Material.LightGrayCandleCake:
case Material.CyanCandleCake:
case Material.PurpleCandleCake:
case Material.BlueCandleCake:
case Material.BrownCandleCake:
case Material.GreenCandleCake:
case Material.RedCandleCake:
case Material.BlackCandleCake:
case Material.AmethystBlock:
case Material.BuddingAmethyst:
case Material.AmethystCluster:
case Material.LargeAmethystBud:
case Material.MediumAmethystBud:
case Material.SmallAmethystBud:
case Material.Tuff:
case Material.Calcite:
case Material.TintedGlass:
case Material.SculkSensor:
case Material.OxidizedCopper:
case Material.WeatheredCopper:
case Material.ExposedCopper:
case Material.CopperBlock:
case Material.CopperOre:
case Material.DeepslateCopperOre:
case Material.OxidizedCutCopper:
case Material.WeatheredCutCopper:
case Material.ExposedCutCopper:
case Material.CutCopper:
case Material.OxidizedCutCopperStairs:
case Material.WeatheredCutCopperStairs:
case Material.ExposedCutCopperStairs:
case Material.CutCopperStairs:
case Material.OxidizedCutCopperSlab:
case Material.WeatheredCutCopperSlab:
case Material.ExposedCutCopperSlab:
case Material.CutCopperSlab:
case Material.WaxedCopperBlock:
case Material.WaxedWeatheredCopper:
case Material.WaxedExposedCopper:
case Material.WaxedOxidizedCopper:
case Material.WaxedOxidizedCutCopper:
case Material.WaxedWeatheredCutCopper:
case Material.WaxedExposedCutCopper:
case Material.WaxedCutCopper:
case Material.WaxedOxidizedCutCopperStairs:
case Material.WaxedWeatheredCutCopperStairs:
case Material.WaxedExposedCutCopperStairs:
case Material.WaxedCutCopperStairs:
case Material.WaxedOxidizedCutCopperSlab:
case Material.WaxedWeatheredCutCopperSlab:
case Material.WaxedExposedCutCopperSlab:
case Material.WaxedCutCopperSlab:
case Material.LightningRod:
case Material.PointedDripstone:
case Material.DripstoneBlock:
case Material.Azalea:
case Material.FloweringAzalea:
case Material.MossCarpet:
case Material.MossBlock:
case Material.RootedDirt:
case Material.Deepslate:
case Material.CobbledDeepslate:
case Material.CobbledDeepslateStairs:
case Material.CobbledDeepslateSlab:
case Material.CobbledDeepslateWall:
case Material.PolishedDeepslate:
case Material.PolishedDeepslateStairs:
case Material.PolishedDeepslateSlab:
case Material.PolishedDeepslateWall:
case Material.DeepslateTiles:
case Material.DeepslateTileStairs:
case Material.DeepslateTileSlab:
case Material.DeepslateTileWall:
case Material.DeepslateBricks:
case Material.DeepslateBrickStairs:
case Material.DeepslateBrickSlab:
case Material.DeepslateBrickWall:
case Material.ChiseledDeepslate:
case Material.CrackedDeepslateBricks:
case Material.CrackedDeepslateTiles:
case Material.InfestedDeepslate:
case Material.SmoothBasalt:
case Material.RawIronBlock:
case Material.RawCopperBlock:
case Material.RawGoldBlock:
case Material.PottedAzaleaBush:
case Material.PottedFloweringAzaleaBush:
return true;
default:
return false;
@ -538,6 +656,7 @@ namespace MinecraftClient.Mapping
case Material.Lava:
case Material.MagmaBlock:
case Material.Campfire:
case Material.PowderSnow:
return true;
default:
return false;

View file

@ -32,7 +32,7 @@ namespace MinecraftClient.Mapping
}
if (!IsOnGround(world, location) && !IsSwimming(world, location))
{
while (!IsOnGround(world, belowFoots) && belowFoots.Y >= 1)
while (!IsOnGround(world, belowFoots) && belowFoots.Y >= 1 + World.GetDimension().minY)
belowFoots = Move(belowFoots, Direction.Down);
location = Move2Steps(location, belowFoots, ref motionY, true).Dequeue();
}
@ -446,6 +446,9 @@ namespace MinecraftClient.Mapping
/// <returns>True if the specified location is on the ground</returns>
public static bool IsOnGround(World world, Location location)
{
if (world.GetChunkColumn(location) == null || world.GetChunkColumn(location).FullyLoaded == false)
return true; // avoid moving downward in a not loaded chunk
return world.GetBlock(Move(location, Direction.Down)).Type.IsSolid()
&& (location.Y <= Math.Truncate(location.Y) + 0.0001);
}

View file

@ -16,11 +16,22 @@ namespace MinecraftClient.Mapping
/// </summary>
private Dictionary<int, Dictionary<int, ChunkColumn>> chunks = new Dictionary<int, Dictionary<int, ChunkColumn>>();
/// <summary>
/// The dimension info of the world
/// </summary>
private static Dimension dimension = new Dimension();
/// <summary>
/// Lock for thread safety
/// </summary>
private readonly ReaderWriterLockSlim chunksLock = new ReaderWriterLockSlim();
/// <summary>
/// Chunk data parsing progress
/// </summary>
public int chunkCnt = 0;
public int chunkLoadNotCompleted = 0;
/// <summary>
/// Read, set or unload the specified chunk column
/// </summary>
@ -78,6 +89,26 @@ namespace MinecraftClient.Mapping
}
}
/// <summary>
/// Set dimension type
/// </summary>
/// <param name="name"> The name of the dimension type</param>
/// <param name="nbt">The dimension type (NBT Tag Compound)</param>
public static void SetDimension(string name, Dictionary<string, object> nbt)
{
// will change in 1.19 and above
dimension = new Dimension(name, nbt);
}
/// <summary>
/// Get current dimension
/// </summary>
/// <returns>Current dimension</returns>
public static Dimension GetDimension()
{
return dimension;
}
/// <summary>
/// Get chunk column at the specified location
/// </summary>

View file

@ -1288,8 +1288,7 @@ namespace MinecraftClient
if (inventories.ContainsKey(windowId) && inventories[windowId].Items.ContainsKey(slotId))
item = inventories[windowId].Items[slotId];
// Inventory update must be after sending packet
bool result = handler.SendWindowAction(windowId, slotId, action, item);
List<Tuple<short, Item>> changedSlots = new List<Tuple<short, Item>>(); // List<Slot ID, Changed Items>
// Update our inventory base on action type
var inventory = GetInventory(windowId);
@ -1340,6 +1339,11 @@ namespace MinecraftClient
inventory.Items[slotId] = playerInventory.Items[-1];
playerInventory.Items.Remove(-1);
}
if (inventory.Items.ContainsKey(slotId))
changedSlots.Add(new Tuple<short, Item>((short)slotId, inventory.Items[slotId]));
else
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
}
else
{
@ -1352,6 +1356,8 @@ namespace MinecraftClient
// Put target slot item to cursor
playerInventory.Items[-1] = inventory.Items[slotId];
inventory.Items.Remove(slotId);
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
}
}
break;
@ -1430,6 +1436,10 @@ namespace MinecraftClient
}
}
}
if (inventory.Items.ContainsKey(slotId))
changedSlots.Add(new Tuple<short, Item>((short)slotId, inventory.Items[slotId]));
else
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
break;
case WindowActionType.ShiftClick:
if (slotId == 0) break;
@ -1457,6 +1467,7 @@ namespace MinecraftClient
// If hotbar already have same item, will put on it first until every stack are full
// If no more same item , will put on the first empty slot (smaller slot id)
// If inventory full, item will not move
int itemCount = inventory.Items[slotId].Count;
if (slotId <= upperEndSlot)
{
// Clicked slot is on upper side inventory, put it to hotbar
@ -1476,11 +1487,16 @@ namespace MinecraftClient
// Can fit into the stack
inventory.Items[_item.Key].Count += inventory.Items[slotId].Count;
inventory.Items.Remove(slotId);
changedSlots.Add(new Tuple<short, Item>((short)_item.Key, inventory.Items[_item.Key]));
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
}
else
{
inventory.Items[slotId].Count -= spaceLeft;
inventory.Items[_item.Key].Count = inventory.Items[_item.Key].Type.StackCount();
changedSlots.Add(new Tuple<short, Item>((short)_item.Key, inventory.Items[_item.Key]));
}
}
}
@ -1499,6 +1515,13 @@ namespace MinecraftClient
var itemTmp = inventory.Items[slotId];
inventory.Items[emptySlot] = new Item(itemTmp.Type, itemTmp.Count, itemTmp.NBT);
inventory.Items.Remove(slotId);
changedSlots.Add(new Tuple<short, Item>((short)emptySlot, inventory.Items[emptySlot]));
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
}
else if (inventory.Items[slotId].Count != itemCount)
{
changedSlots.Add(new Tuple<short, Item>((short)slotId, inventory.Items[slotId]));
}
}
}
@ -1522,11 +1545,16 @@ namespace MinecraftClient
// Can fit into the stack
inventory.Items[_item.Key].Count += inventory.Items[slotId].Count;
inventory.Items.Remove(slotId);
changedSlots.Add(new Tuple<short, Item>((short)_item.Key, inventory.Items[_item.Key]));
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
}
else
{
inventory.Items[slotId].Count -= spaceLeft;
inventory.Items[_item.Key].Count = inventory.Items[_item.Key].Type.StackCount();
changedSlots.Add(new Tuple<short, Item>((short)_item.Key, inventory.Items[_item.Key]));
}
}
}
@ -1546,6 +1574,13 @@ namespace MinecraftClient
var itemTmp = inventory.Items[slotId];
inventory.Items[emptySlot] = new Item(itemTmp.Type, itemTmp.Count, itemTmp.NBT);
inventory.Items.Remove(slotId);
changedSlots.Add(new Tuple<short, Item>((short)emptySlot, inventory.Items[emptySlot]));
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
}
else if (inventory.Items[slotId].Count != itemCount)
{
changedSlots.Add(new Tuple<short, Item>((short)slotId, inventory.Items[slotId]));
}
}
}
@ -1553,18 +1588,26 @@ namespace MinecraftClient
break;
case WindowActionType.DropItem:
if (inventory.Items.ContainsKey(slotId))
{
inventory.Items[slotId].Count--;
changedSlots.Add(new Tuple<short, Item>((short)slotId, inventory.Items[slotId]));
}
if (inventory.Items[slotId].Count <= 0)
{
inventory.Items.Remove(slotId);
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
}
break;
case WindowActionType.DropItemStack:
inventory.Items.Remove(slotId);
changedSlots.Add(new Tuple<short, Item>((short)slotId, null));
break;
}
}
return result;
return handler.SendWindowAction(windowId, slotId, action, item, changedSlots, inventories[windowId].StateID);
}
/// <summary>
@ -2127,11 +2170,12 @@ namespace MinecraftClient
/// </summary>
/// <param name="inventoryID">Inventory ID</param>
/// <param name="itemList">Item list, key = slot ID, value = Item information</param>
public void OnWindowItems(byte inventoryID, Dictionary<int, Inventory.Item> itemList)
public void OnWindowItems(byte inventoryID, Dictionary<int, Inventory.Item> itemList, int stateId)
{
if (inventories.ContainsKey(inventoryID))
{
inventories[inventoryID].Items = itemList;
inventories[inventoryID].StateID = stateId;
DispatchBotEvent(bot => bot.OnInventoryUpdate(inventoryID));
}
}
@ -2142,8 +2186,11 @@ namespace MinecraftClient
/// <param name="inventoryID">Window ID</param>
/// <param name="slotID">Slot ID</param>
/// <param name="item">Item (may be null for empty slot)</param>
public void OnSetSlot(byte inventoryID, short slotID, Item item)
public void OnSetSlot(byte inventoryID, short slotID, Item item, int stateId)
{
if (inventories.ContainsKey(inventoryID))
inventories[inventoryID].StateID = stateId;
// Handle inventoryID -2 - Add item to player inventory without animation
if (inventoryID == 254)
inventoryID = 0;
@ -2591,7 +2638,7 @@ namespace MinecraftClient
/// <param name="action">0 to create/update an item. 1 to remove an item.</param>
/// <param name="objectivename">The name of the objective the score belongs to</param>
/// <param name="value">he score to be displayed next to the entry. Only sent when Action does not equal 1.</param>
public void OnUpdateScore(string entityname, byte action, string objectivename, int value)
public void OnUpdateScore(string entityname, int action, string objectivename, int value)
{
DispatchBotEvent(bot => bot.OnUpdateScore(entityname, action, objectivename, value));
}

View file

@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -8,6 +9,9 @@ using System.Runtime.InteropServices;
using System.Threading;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Protocol.Session;
using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Mapping.BlockPalettes;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.WinAPI;
using MinecraftClient.Protocol.Keys;
using System.Security.Cryptography;
@ -123,6 +127,82 @@ namespace MinecraftClient
return;
}
if (args.Contains("--generate"))
{
string dataGenerator = "";
string dataPath = "";
foreach (string argument in args)
{
if (argument.StartsWith("--") && !argument.Contains("--generate"))
{
if (!argument.Contains("="))
throw new ArgumentException(Translations.Get("error.setting.argument_syntax", argument));
string[] argParts = argument.Substring(2).Split('=');
string argName = argParts[0].Trim();
string argValue = argParts[1].Replace("\"", "").Trim();
if (argName == "data-path")
{
Console.WriteLine(dataPath);
dataPath = argValue;
}
if (argName == "data-generator")
{
dataGenerator = argValue;
}
}
}
if (string.IsNullOrEmpty(dataGenerator) || !(dataGenerator.ToLower().Equals("entity") || dataGenerator.ToLower().Equals("item") || dataGenerator.ToLower().Equals("block")))
{
Console.WriteLine(Translations.Get("error.generator.invalid"));
Console.WriteLine(Translations.Get("error.usage") + " MinecraftClient.exe --data-generator=<entity|item|block> --data-path=\"<path to resources.json>\"");
return;
}
if (string.IsNullOrEmpty(dataPath))
{
Console.WriteLine(Translations.Get("error.missing.argument", "--data-path"));
Console.WriteLine(Translations.Get("error.usage") + " MinecraftClient.exe --data-generator=<entity|item|block> --data-path=\"<path to resources.json>\"");
return;
}
if (!File.Exists(dataPath))
{
Console.WriteLine(Translations.Get("error.generator.path", dataPath));
return;
}
if (!dataPath.EndsWith(".json"))
{
Console.WriteLine(Translations.Get("error.generator.json", dataPath));
return;
}
Console.WriteLine(Translations.Get("mcc.generator.generating", dataGenerator, dataPath));
switch (dataGenerator)
{
case "entity":
EntityPaletteGenerator.GenerateEntityTypes(dataPath);
break;
case "item":
ItemPaletteGenerator.GenerateItemType(dataPath);
break;
case "block":
BlockPaletteGenerator.GenerateBlockPalette(dataPath);
break;
}
Console.WriteLine(Translations.Get("mcc.generator.done", dataGenerator, dataPath));
return;
}
try
{
Settings.LoadArguments(args);

View file

@ -450,6 +450,7 @@ namespace MinecraftClient.Protocol.Handlers
// NBT root name
string rootName = Encoding.ASCII.GetString(ReadData(ReadNextUShort(cache), cache));
if (!String.IsNullOrEmpty(rootName))
nbtData[""] = rootName;
}
@ -706,10 +707,13 @@ namespace MinecraftClient.Protocol.Handlers
// NBT root name
string rootName = null;
if (nbt.ContainsKey(""))
rootName = nbt[""] as string;
if (rootName == null)
rootName = "";
bytes.AddRange(GetUShort((ushort)rootName.Length));
bytes.AddRange(Encoding.ASCII.GetBytes(rootName));
}
@ -1010,10 +1014,10 @@ namespace MinecraftClient.Protocol.Handlers
{
// MC 1.13 and greater
if (item == null || item.IsEmpty)
slotData.Add(0); // No item
slotData.AddRange(GetBool(false)); // No item
else
{
slotData.Add(1); // Item is present
slotData.AddRange(GetBool(true)); // Item is present
slotData.AddRange(GetVarInt(itemPalette.ToId(item.Type)));
slotData.Add((byte)item.Count);
slotData.AddRange(GetNbt(item.NBT));
@ -1034,6 +1038,24 @@ namespace MinecraftClient.Protocol.Handlers
return slotData.ToArray();
}
/// <summary>
/// Get a byte array representing an array of item slots
/// </summary>
/// <param name="items">Items</param>
/// <param name="itemPalette">Item Palette</param>
/// <returns>Array of Item slot representations</returns>
public byte[] GetSlotsArray(Dictionary<int, Item> items, ItemPalette itemPalette)
{
byte[] slotsArray = new byte[items.Count];
foreach (KeyValuePair<int, Item> item in items)
{
slotsArray = ConcatBytes(slotsArray, GetShort((short)item.Key), GetItemSlot(item.Value, itemPalette));
}
return slotsArray;
}
/// <summary>
/// Get protocol block face from Direction
/// </summary>
@ -1076,6 +1098,11 @@ namespace MinecraftClient.Protocol.Handlers
return result.ToArray();
}
/// <summary>
/// Convert a byte array to an hexadecimal string representation (for debugging purposes)
/// </summary>
/// <param name="bytes">Byte array</param>
/// <returns>String representation</returns>
public string ByteArrayToString(byte[] bytes)
{
return BitConverter.ToString(bytes).Replace("-", " ");

View file

@ -64,7 +64,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x37, PacketTypesIn.FacePlayer },
{ 0x38, PacketTypesIn.PlayerPositionAndLook },
{ 0x39, PacketTypesIn.UnlockRecipes },
{ 0x3A, PacketTypesIn.DestroyEntity },
{ 0x3A, PacketTypesIn.DestroyEntities },
{ 0x3B, PacketTypesIn.RemoveEntityEffect },
{ 0x3C, PacketTypesIn.ResourcePackSend },
{ 0x3D, PacketTypesIn.Respawn },

View file

@ -64,7 +64,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x37, PacketTypesIn.FacePlayer },
{ 0x38, PacketTypesIn.PlayerPositionAndLook },
{ 0x39, PacketTypesIn.UnlockRecipes },
{ 0x3A, PacketTypesIn.DestroyEntity },
{ 0x3A, PacketTypesIn.DestroyEntities },
{ 0x3B, PacketTypesIn.RemoveEntityEffect },
{ 0x3C, PacketTypesIn.ResourcePackSend },
{ 0x3D, PacketTypesIn.Respawn },

View file

@ -62,7 +62,7 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
{ 0x35, PacketTypesIn.FacePlayer }, // (Wiki name: Player Look At)
{ 0x36, PacketTypesIn.PlayerPositionAndLook }, // (Wiki name: Player Position)
{ 0x37, PacketTypesIn.UnlockRecipes }, // (Wiki name: Recipe)
{ 0x38, PacketTypesIn.DestroyEntity }, // (Wiki name: Remove Entites)
{ 0x38, PacketTypesIn.DestroyEntities }, // (Wiki name: Remove Entites)
{ 0x39, PacketTypesIn.RemoveEntityEffect },
{ 0x3A, PacketTypesIn.ResourcePackSend }, // (Wiki name: Resource Pack)
{ 0x3B, PacketTypesIn.Respawn }, // Changed in 1.19 (Heavy changes) - DONE

View file

@ -112,7 +112,6 @@ namespace MinecraftClient.Protocol.Handlers
WorldBorderCenter,
ActionBar,
Tags,
DestroyEntity, // For 1.17+
DeathCombatEvent,
EnterCombatEvent,
EndCombatEvent,

View file

@ -729,7 +729,7 @@ namespace MinecraftClient.Protocol.Handlers
return false; //Currently not implemented
}
public bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item)
public bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item, List<Tuple<short, Item>> changedSlots, int stateId)
{
return false; //Currently not implemented
}

View file

@ -12,7 +12,6 @@ using MinecraftClient.Mapping.BlockPalettes;
using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Inventory;
using System.Data.SqlClient;
using System.Diagnostics;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.PacketPalettes;
@ -92,19 +91,19 @@ namespace MinecraftClient.Protocol.Handlers
this.log = handler.GetLogger();
this.randomGen = RandomNumberGenerator.Create();
if (handler.GetTerrainEnabled() && protocolversion > MC_1_16_5_Version)
if (handler.GetTerrainEnabled() && protocolversion > MC_1_18_2_Version)
{
log.Error(Translations.Get("extra.terrainandmovement_disabled"));
handler.SetTerrainEnabled(false);
}
if (handler.GetInventoryEnabled() && (protocolversion < MC_1_10_Version || protocolversion > MC_1_16_5_Version))
if (handler.GetInventoryEnabled() && (protocolversion < MC_1_10_Version || protocolversion > MC_1_18_2_Version))
{
log.Error(Translations.Get("extra.inventory_disabled"));
handler.SetInventoryEnabled(false);
}
if (handler.GetEntityHandlingEnabled() && (protocolversion < MC_1_10_Version || protocolversion > MC_1_16_5_Version))
if (handler.GetEntityHandlingEnabled() && (protocolversion < MC_1_10_Version || protocolversion > MC_1_18_2_Version))
{
log.Error(Translations.Get("extra.entity_disabled"));
handler.SetEntityHandlingEnabled(false);
@ -113,8 +112,11 @@ namespace MinecraftClient.Protocol.Handlers
// Block palette
if (protocolversion >= MC_1_13_Version)
{
if (protocolVersion > MC_1_16_5_Version && handler.GetTerrainEnabled())
if (protocolVersion > MC_1_18_2_Version && handler.GetTerrainEnabled())
throw new NotImplementedException(Translations.Get("exception.palette.block"));
if (protocolVersion >= MC_1_17_Version)
Block.Palette = new Palette117();
else if (protocolVersion >= MC_1_16_Version)
if (protocolVersion >= MC_1_16_Version)
Block.Palette = new Palette116();
else if (protocolVersion >= MC_1_15_Version)
@ -128,8 +130,11 @@ namespace MinecraftClient.Protocol.Handlers
// Entity palette
if (protocolversion >= MC_1_13_Version)
{
if (protocolversion > MC_1_16_5_Version && handler.GetEntityHandlingEnabled())
if (protocolversion > MC_1_18_2_Version && handler.GetEntityHandlingEnabled())
throw new NotImplementedException(Translations.Get("exception.palette.entity"));
if (protocolversion >= MC_1_17_Version)
entityPalette = new EntityPalette117();
else if (protocolversion >= MC_1_16_2_Version)
if (protocolversion >= MC_1_16_2_Version)
entityPalette = new EntityPalette1162();
else if (protocolversion >= MC_1_16_Version)
@ -143,10 +148,15 @@ namespace MinecraftClient.Protocol.Handlers
else entityPalette = new EntityPalette112();
// Item palette
if (protocolversion >= MC_1_16_Version)
if (protocolversion >= MC_1_16_2_Version)
{
if (protocolversion > MC_1_16_5_Version && handler.GetInventoryEnabled())
if (protocolversion > MC_1_18_2_Version && handler.GetInventoryEnabled())
throw new NotImplementedException(Translations.Get("exception.palette.item"));
if (protocolversion >= MC_1_18_1_Version)
itemPalette = new ItemPalette118();
else if (protocolversion >= MC_1_17_Version)
itemPalette = new ItemPalette117();
else if (protocolversion >= MC_1_16_2_Version)
if (protocolversion >= MC_1_16_2_Version)
itemPalette = new ItemPalette1162();
else itemPalette = new ItemPalette1161();
@ -229,6 +239,7 @@ namespace MinecraftClient.Protocol.Handlers
packetData.Clear();
int size = dataTypes.ReadNextVarIntRAW(socketWrapper); //Packet size
byte[] rawpacket = socketWrapper.ReadDataRAW(size); //Packet contents
for (int i = 0; i < rawpacket.Length; i++)
packetData.Enqueue(rawpacket[i]);
@ -341,9 +352,8 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolversion >= MC_1_16_Version)
currentDimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above
// Implementation in PR#1943
// if (protocolversion >= MC_1_16_2_Version)
// handler.GetWorld().SetDimension(currentDimensionName, currentDimensionType);
if (protocolversion >= MC_1_16_2_Version)
World.SetDimension(currentDimensionName, currentDimensionType);
if (protocolversion >= MC_1_15_Version)
dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above
@ -430,13 +440,13 @@ namespace MinecraftClient.Protocol.Handlers
break;
case PacketTypesIn.Respawn:
string? dimensionNameInRespawn = null;
Dictionary<string, object>? dimensionTypeInRespawn = null;
Dictionary<string, object> dimensionTypeInRespawn = null;
if (protocolversion >= MC_1_16_Version)
{
if (protocolversion >= MC_1_19_Version)
dataTypes.ReadNextString(packetData); // Dimension Type: Identifier
else if (protocolversion >= MC_1_16_2_Version)
currentDimensionType = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
dimensionTypeInRespawn = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
else
dataTypes.ReadNextString(packetData);
this.currentDimension = 0;
@ -449,9 +459,8 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolversion >= MC_1_16_Version)
dimensionNameInRespawn = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above
// Implementation in PR#1943
// if (protocolversion >= MC_1_16_2_Version)
// handler.GetWorld().SetDimension(currentDimensionName, currentDimensionType);
if (protocolversion >= MC_1_16_2_Version)
World.SetDimension(dimensionNameInRespawn, dimensionTypeInRespawn);
if (protocolversion < MC_1_14_Version)
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
@ -509,56 +518,88 @@ namespace MinecraftClient.Protocol.Handlers
SendPacket(PacketTypesOut.TeleportConfirm, dataTypes.GetVarInt(teleportID));
}
if (protocolversion >= MC_1_17_Version) dataTypes.ReadNextBool(packetData);
if (protocolversion >= MC_1_17_Version)
dataTypes.ReadNextBool(packetData); // Dismount Vehicle - 1.17 and above
break;
case PacketTypesIn.ChunkData: //TODO implement for 1.17, bit mask is not limited to 0-15 anymore
case PacketTypesIn.ChunkData:
if (handler.GetTerrainEnabled())
{
int chunkX = dataTypes.ReadNextInt(packetData);
int chunkZ = dataTypes.ReadNextInt(packetData);
bool chunksContinuous = dataTypes.ReadNextBool(packetData);
if (protocolversion >= MC_1_16_Version && protocolversion <= MC_1_16_1_Version)
dataTypes.ReadNextBool(packetData); // Ignore old data - 1.16 to 1.16.1 only
ushort chunkMask = protocolversion >= MC_1_9_Version
? (ushort)dataTypes.ReadNextVarInt(packetData)
: dataTypes.ReadNextUShort(packetData);
if (protocolversion < MC_1_8_Version)
if (protocolversion >= MC_1_17_Version)
{
ushort addBitmap = dataTypes.ReadNextUShort(packetData);
int compressedDataSize = dataTypes.ReadNextInt(packetData);
byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData);
byte[] decompressed = ZlibUtils.Decompress(compressed);
ulong[]? verticalStripBitmask = null;
if (protocolversion == MC_1_17_Version || protocolversion == MC_1_17_1_Version)
verticalStripBitmask = dataTypes.ReadNextULongArray(packetData); // Bit Mask Le:ngth and Primary Bit Mask
dataTypes.ReadNextNbt(packetData); // Heightmaps
if (protocolversion == MC_1_17_Version || protocolversion == MC_1_17_1_Version)
{
int biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length
for (int i = 0; i < biomesLength; i++)
{
dataTypes.SkipNextVarInt(packetData); // Biomes
}
}
int dataSize = dataTypes.ReadNextVarInt(packetData); // Size
Interlocked.Increment(ref handler.GetWorld().chunkCnt);
Interlocked.Increment(ref handler.GetWorld().chunkLoadNotCompleted);
new Task(() =>
{
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue<byte>(decompressed));
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, verticalStripBitmask, packetData);
Interlocked.Decrement(ref handler.GetWorld().chunkLoadNotCompleted);
}).Start();
}
else
{
if (protocolversion >= MC_1_14_Version)
dataTypes.ReadNextNbt(packetData); // Heightmaps - 1.14 and above
int biomesLength = 0;
if (protocolversion >= MC_1_16_2_Version)
if (chunksContinuous)
biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length - 1.16.2 and above
if (protocolversion >= MC_1_15_Version && chunksContinuous)
bool chunksContinuous = dataTypes.ReadNextBool(packetData);
if (protocolversion >= MC_1_16_Version && protocolversion <= MC_1_16_1_Version)
dataTypes.ReadNextBool(packetData); // Ignore old data - 1.16 to 1.16.1 only
ushort chunkMask = protocolversion >= MC_1_9_Version
? (ushort)dataTypes.ReadNextVarInt(packetData)
: dataTypes.ReadNextUShort(packetData);
if (protocolversion < MC_1_8_Version)
{
if (protocolversion >= MC_1_16_2_Version)
ushort addBitmap = dataTypes.ReadNextUShort(packetData);
int compressedDataSize = dataTypes.ReadNextInt(packetData);
byte[] compressed = dataTypes.ReadData(compressedDataSize, packetData);
byte[] decompressed = ZlibUtils.Decompress(compressed);
new Task(() =>
{
for (int i = 0; i < biomesLength; i++)
{
// Biomes - 1.16.2 and above
// Don't use ReadNextVarInt because it cost too much time
dataTypes.SkipNextVarInt(packetData);
}
}
else dataTypes.ReadData(1024 * 4, packetData); // Biomes - 1.15 and above
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, addBitmap, currentDimension == 0, chunksContinuous, currentDimension, new Queue<byte>(decompressed));
}).Start();
}
int dataSize = dataTypes.ReadNextVarInt(packetData);
new Task(() =>
else
{
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData);
}).Start();
if (protocolversion >= MC_1_14_Version)
dataTypes.ReadNextNbt(packetData); // Heightmaps - 1.14 and above
int biomesLength = 0;
if (protocolversion >= MC_1_16_2_Version)
if (chunksContinuous)
biomesLength = dataTypes.ReadNextVarInt(packetData); // Biomes length - 1.16.2 and above
if (protocolversion >= MC_1_15_Version && chunksContinuous)
{
if (protocolversion >= MC_1_16_2_Version)
{
for (int i = 0; i < biomesLength; i++)
{
// Biomes - 1.16.2 and above
// Don't use ReadNextVarInt because it cost too much time
dataTypes.SkipNextVarInt(packetData);
}
}
else dataTypes.ReadData(1024 * 4, packetData); // Biomes - 1.15 and above
}
int dataSize = dataTypes.ReadNextVarInt(packetData);
new Task(() =>
{
pTerrain.ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, currentDimension, packetData);
}).Start();
}
}
}
break;
@ -666,7 +707,7 @@ namespace MinecraftClient.Protocol.Handlers
int sectionX = (int)(chunkSection >> 42);
int sectionY = (int)((chunkSection << 44) >> 44);
int sectionZ = (int)((chunkSection << 22) >> 42);
dataTypes.ReadNextBool(packetData); // Useless boolean
dataTypes.ReadNextBool(packetData); // Useless boolean (Related to light update)
int blocksSize = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < blocksSize; i++)
{
@ -820,6 +861,13 @@ namespace MinecraftClient.Protocol.Handlers
{
int chunkX = dataTypes.ReadNextInt(packetData);
int chunkZ = dataTypes.ReadNextInt(packetData);
// Warning: It is legal to include unloaded chunks in the UnloadChunk packet.
// Since chunks that have not been loaded are not recorded, this may result
// in loading chunks that should be unloaded and inaccurate statistics.
if (handler.GetWorld()[chunkX, chunkZ] != null)
Interlocked.Decrement(ref handler.GetWorld().chunkCnt);
handler.GetWorld()[chunkX, chunkZ] = null;
}
break;
@ -985,24 +1033,45 @@ namespace MinecraftClient.Protocol.Handlers
if (handler.GetInventoryEnabled())
{
byte windowId = dataTypes.ReadNextByte(packetData);
short elements = dataTypes.ReadNextShort(packetData);
int stateId = -1;
int elements = 0;
if (protocolversion >= MC_1_17_1_Version)
{
// State ID and Elements as VarInt - 1.17.1 and above
stateId = dataTypes.ReadNextVarInt(packetData);
elements = dataTypes.ReadNextVarInt(packetData);
}
else
{
// Elements as Short - 1.17.0 and below
dataTypes.ReadNextShort(packetData);
}
Dictionary<int, Item> inventorySlots = new Dictionary<int, Item>();
for (short slotId = 0; slotId < elements; slotId++)
for (int slotId = 0; slotId < elements; slotId++)
{
Item item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
if (item != null)
inventorySlots[slotId] = item;
}
handler.OnWindowItems(windowId, inventorySlots);
if (protocolversion >= MC_1_17_1_Version) // Carried Item - 1.17.1 and above
dataTypes.ReadNextItemSlot(packetData, itemPalette);
handler.OnWindowItems(windowId, inventorySlots, stateId);
}
break;
case PacketTypesIn.SetSlot:
if (handler.GetInventoryEnabled())
{
byte windowID = dataTypes.ReadNextByte(packetData);
int stateId = -1;
if (protocolversion >= MC_1_17_1_Version)
stateId = dataTypes.ReadNextVarInt(packetData); // State ID - 1.17.1 and above
short slotID = dataTypes.ReadNextShort(packetData);
Item item = dataTypes.ReadNextItemSlot(packetData, itemPalette);
handler.OnSetSlot(windowID, slotID, item);
handler.OnSetSlot(windowID, slotID, item, stateId);
}
break;
case PacketTypesIn.WindowConfirmation:
@ -1024,7 +1093,9 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolversion >= MC_1_17_Version)
{
forced = dataTypes.ReadNextBool(packetData);
String forcedMessage = ChatParser.ParseText(dataTypes.ReadNextString(packetData));
string forcedMessage = ChatParser.ParseText(dataTypes.ReadNextString(packetData));
dataTypes.ReadNextBool(packetData); // Has Prompt Message (Boolean) - 1.17 and above
dataTypes.ReadNextString(packetData); // Prompt Message (Optional Chat) - 1.17 and above
}
// Some server plugins may send invalid resource packs to probe the client and we need to ignore them (issue #1056)
if (!url.StartsWith("http") && hash.Length != 40) // Some server may have null hash value
@ -1121,19 +1192,15 @@ namespace MinecraftClient.Protocol.Handlers
case PacketTypesIn.DestroyEntities:
if (handler.GetEntityHandlingEnabled())
{
int EntityCount = dataTypes.ReadNextVarInt(packetData);
int[] EntitiesList = new int[EntityCount];
for (int i = 0; i < EntityCount; i++)
int entityCount = 1; // 1.17.0 has only one entity per packet
if (protocolversion != MC_1_17_Version)
entityCount = dataTypes.ReadNextVarInt(packetData); // All other versions have a "count" field
int[] entityList = new int[entityCount];
for (int i = 0; i < entityCount; i++)
{
EntitiesList[i] = dataTypes.ReadNextVarInt(packetData);
entityList[i] = dataTypes.ReadNextVarInt(packetData);
}
handler.OnDestroyEntities(EntitiesList);
}
break;
case PacketTypesIn.DestroyEntity:
if (handler.GetEntityHandlingEnabled())
{
handler.OnDestroyEntities(new[] { dataTypes.ReadNextVarInt(packetData) });
handler.OnDestroyEntities(entityList);
}
break;
case PacketTypesIn.EntityPosition:
@ -1206,7 +1273,16 @@ namespace MinecraftClient.Protocol.Handlers
{
int EntityID = dataTypes.ReadNextVarInt(packetData);
Dictionary<int, object> metadata = dataTypes.ReadNextMetadata(packetData, itemPalette);
int healthField = protocolversion >= MC_1_14_Version ? 8 : 7; // Health is field no. 7 in 1.10+ and 8 in 1.14+
// See https://wiki.vg/Entity_metadata#Living_Entity
int healthField = 7; // From 1.10 to 1.13.2
if (protocolversion >= MC_1_14_Version)
healthField = 8; // 1.14 and above
if (protocolversion >= MC_1_17_Version)
healthField = 9; // 1.17 and above
if (protocolversion > MC_1_18_2_Version)
throw new NotImplementedException(Translations.Get("exception.palette.healthfield"));
if (metadata.ContainsKey(healthField) && metadata[healthField] != null && metadata[healthField].GetType() == typeof(float))
handler.OnEntityHealth(EntityID, (float)metadata[healthField]);
handler.OnEntityMetadata(EntityID, metadata);
@ -1292,7 +1368,9 @@ namespace MinecraftClient.Protocol.Handlers
break;
case PacketTypesIn.UpdateScore:
string entityname = dataTypes.ReadNextString(packetData);
byte action3 = dataTypes.ReadNextByte(packetData);
int action3 = protocolversion >= MC_1_18_2_Version
? dataTypes.ReadNextVarInt(packetData)
: dataTypes.ReadNextByte(packetData);
string objectivename2 = string.Empty;
int value = -1;
if (action3 != 1 || protocolversion >= MC_1_8_Version)
@ -1995,7 +2073,12 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolversion >= MC_1_9_Version)
fields.AddRange(dataTypes.GetVarInt(mainHand));
if (protocolversion >= MC_1_17_Version)
fields.Add(0); // Enables text filtering. Always false
{
if (protocolversion >= MC_1_18_1_Version)
fields.Add(0); // 1.18 and above - Enable text filtering. (Always false)
else
fields.Add(1); // 1.17 and 1.17.1 - Disable text filtering. (Always true)
}
if (protocolversion >= MC_1_18_1_Version)
fields.Add(1); // 1.18 and above - Allow server listings
SendPacket(PacketTypesOut.ClientSettings, fields);
@ -2250,7 +2333,7 @@ namespace MinecraftClient.Protocol.Handlers
catch (ObjectDisposedException) { return false; }
}
public bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item)
public bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item, List<Tuple<short, Item>> changedSlots, int stateId)
{
try
{
@ -2286,14 +2369,48 @@ namespace MinecraftClient.Protocol.Handlers
}
List<byte> packet = new List<byte>();
packet.Add((byte)windowId);
packet.AddRange(dataTypes.GetShort((short)slotId));
packet.Add(button);
if (protocolversion < MC_1_17_Version) packet.AddRange(dataTypes.GetShort(actionNumber));
packet.Add((byte)windowId); // Window ID
// 1.18+
if (protocolversion >= MC_1_18_1_Version)
{
packet.AddRange(dataTypes.GetVarInt(stateId)); // State ID
packet.AddRange(dataTypes.GetShort((short)slotId)); // Slot ID
}
// 1.17.1
else if (protocolversion == MC_1_17_1_Version)
{
packet.AddRange(dataTypes.GetShort((short)slotId)); // Slot ID
packet.AddRange(dataTypes.GetVarInt(stateId)); // State ID
}
// Older
else
{
packet.AddRange(dataTypes.GetShort((short)slotId)); // Slot ID
}
packet.Add(button); // Button
if (protocolversion < MC_1_17_Version)
packet.AddRange(dataTypes.GetShort(actionNumber));
if (protocolversion >= MC_1_9_Version)
packet.AddRange(dataTypes.GetVarInt(mode));
packet.AddRange(dataTypes.GetVarInt(mode)); // Mode
else packet.Add(mode);
packet.AddRange(dataTypes.GetItemSlot(item, itemPalette));
// 1.17+ Array of changed slots
if (protocolversion >= MC_1_17_Version)
{
packet.AddRange(dataTypes.GetVarInt(changedSlots.Count)); // Length of the array
foreach (var slot in changedSlots)
{
packet.AddRange(dataTypes.GetShort(slot.Item1)); // slot ID
packet.AddRange(dataTypes.GetItemSlot(slot.Item2, itemPalette)); // slot Data
}
}
packet.AddRange(dataTypes.GetItemSlot(item, itemPalette)); // Carried item (Clicked item)
SendPacket(PacketTypesOut.ClickWindow, packet);
return true;
}

View file

@ -28,7 +28,188 @@ namespace MinecraftClient.Protocol.Handlers
}
/// <summary>
/// Process chunk column data from the server and (un)load the chunk from the Minecraft world
/// Reading the "Block states" field: consists of 4096 entries, representing all the blocks in the chunk section.
/// </summary>
/// <param name="chunk">Blocks will store in this chunk</param>
/// <param name="cache">Cache for reading data</param>
private Chunk ReadBlockStatesField(ref Chunk chunk, Queue<byte> cache)
{
// read Block states (Type: Paletted Container)
byte bitsPerEntry = dataTypes.ReadNextByte(cache);
// 1.18(1.18.1) add a pattle named "Single valued" to replace the vertical strip bitmask in the old
if (bitsPerEntry == 0 && protocolversion >= Protocol18Handler.MC_1_18_1_Version)
{
// Palettes: Single valued - 1.18(1.18.1) and above
ushort value = (ushort)dataTypes.ReadNextVarInt(cache);
dataTypes.SkipNextVarInt(cache); // Data Array Length will be zero
// Empty chunks will not be stored
if (new Block(value).Type == Material.Air)
return null;
for (int blockY = 0; blockY < Chunk.SizeY; blockY++)
{
for (int blockZ = 0; blockZ < Chunk.SizeZ; blockZ++)
{
for (int blockX = 0; blockX < Chunk.SizeX; blockX++)
{
chunk[blockX, blockY, blockZ] = new Block(value);
}
}
}
}
else
{
// Palettes: Indirect or Direct
bool usePalette = (bitsPerEntry <= 8);
// Indirect Mode: For block states with bits per entry <= 4, 4 bits are used to represent a block.
if (bitsPerEntry < 4) bitsPerEntry = 4;
// Direct Mode: Bit mask covering bitsPerEntry bits
// EG, if bitsPerEntry = 5, valueMask = 00011111 in binary
uint valueMask = (uint)((1 << bitsPerEntry) - 1);
int paletteLength = 0; // Assume zero when length is absent
if (usePalette) paletteLength = dataTypes.ReadNextVarInt(cache);
int[] palette = new int[paletteLength];
for (int i = 0; i < paletteLength; i++)
palette[i] = dataTypes.ReadNextVarInt(cache);
// Block IDs are packed in the array of 64-bits integers
ulong[] dataArray = dataTypes.ReadNextULongArray(cache);
int longIndex = 0;
int startOffset = 0 - bitsPerEntry;
for (int blockY = 0; blockY < Chunk.SizeY; blockY++)
{
for (int blockZ = 0; blockZ < Chunk.SizeZ; blockZ++)
{
for (int blockX = 0; blockX < Chunk.SizeX; blockX++)
{
// NOTICE: In the future a single ushort may not store the entire block id;
// the Block class may need to change if block state IDs go beyond 65535
ushort blockId;
// Calculate location of next block ID inside the array of Longs
startOffset += bitsPerEntry;
if ((startOffset + bitsPerEntry) > 64)
{
// In MC 1.16+, padding is applied to prevent overlapping between Longs:
// [ LONG INTEGER ][ LONG INTEGER ]
// [Block][Block][Block]XXXXX[Block][Block][Block]XXXXX
// When overlapping, move forward to the beginning of the next Long
startOffset = 0;
longIndex++;
}
// Extract Block ID
blockId = (ushort)((dataArray[longIndex] >> startOffset) & valueMask);
// Map small IDs to actual larger block IDs
if (usePalette)
{
if (paletteLength <= blockId)
{
int blockNumber = (blockY * Chunk.SizeZ + blockZ) * Chunk.SizeX + blockX;
throw new IndexOutOfRangeException(String.Format("Block ID {0} is outside Palette range 0-{1}! (bitsPerBlock: {2}, blockNumber: {3})",
blockId,
paletteLength - 1,
bitsPerEntry,
blockNumber));
}
blockId = (ushort)palette[blockId];
}
// We have our block, save the block into the chunk
chunk[blockX, blockY, blockZ] = new Block(blockId);
}
}
}
}
return chunk;
}
/// <summary>
/// Process chunk column data from the server and (un)load the chunk from the Minecraft world - 1.17 and above
/// </summary>
/// <param name="chunkX">Chunk X location</param>
/// <param name="chunkZ">Chunk Z location</param>
/// <param name="verticalStripBitmask">Chunk mask for reading data, store in bitset, used in 1.17 and 1.17.1</param>
/// <param name="cache">Cache for reading chunk data</param>
public void ProcessChunkColumnData(int chunkX, int chunkZ, ulong[] verticalStripBitmask, Queue<byte> cache)
{
var world = handler.GetWorld();
int chunkColumnSize = (World.GetDimension().height + 15) / 16; // Round up
if (protocolversion >= Protocol18Handler.MC_1_17_Version)
{
// 1.17 and above chunk format
// Unloading chunks is handled by a separate packet
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
{
// 1.18 and above always contains all chunk section in data
// 1.17 and 1.17.1 need vertical strip bitmask to know if the chunk section is included
if ((protocolversion >= Protocol18Handler.MC_1_18_1_Version) ||
(((protocolversion == Protocol18Handler.MC_1_17_Version) ||
(protocolversion == Protocol18Handler.MC_1_17_1_Version)) &&
((verticalStripBitmask[chunkY / 64] & (1UL << (chunkY % 64))) != 0)))
{
// Non-air block count inside chunk section, for lighting purposes
int blockCnt = dataTypes.ReadNextShort(cache);
// Read Block states (Type: Paletted Container)
Chunk chunk = new Chunk();
ReadBlockStatesField(ref chunk, cache);
//We have our chunk, save the chunk into the world
handler.InvokeOnMainThread(() =>
{
if (handler.GetWorld()[chunkX, chunkZ] == null)
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn(chunkColumnSize);
handler.GetWorld()[chunkX, chunkZ][chunkY] = chunk;
});
// Skip Read Biomes (Type: Paletted Container) - 1.18(1.18.1) and above
if (protocolversion >= Protocol18Handler.MC_1_18_1_Version)
{
byte bitsPerEntryBiome = dataTypes.ReadNextByte(cache); // Bits Per Entry
if (bitsPerEntryBiome == 0)
{
dataTypes.SkipNextVarInt(cache); // Value
dataTypes.SkipNextVarInt(cache); // Data Array Length
// Data Array must be empty
}
else
{
if (bitsPerEntryBiome <= 3)
{
int paletteLength = dataTypes.ReadNextVarInt(cache); // Palette Length
for (int i = 0; i < paletteLength; i++)
dataTypes.SkipNextVarInt(cache); // Palette
}
int dataArrayLength = dataTypes.ReadNextVarInt(cache); // Data Array Length
dataTypes.ReadData(dataArrayLength * 8, cache); // Data Array
}
}
}
}
// Don't worry about skipping remaining data since there is no useful data afterwards in 1.9
// (plus, it would require parsing the tile entity lists' NBT)
}
handler.GetWorld()[chunkX, chunkZ].FullyLoaded = true;
}
/// <summary>
/// Process chunk column data from the server and (un)load the chunk from the Minecraft world - 1.17 below
/// </summary>
/// <param name="chunkX">Chunk X location</param>
/// <param name="chunkZ">Chunk Z location</param>
@ -40,11 +221,12 @@ namespace MinecraftClient.Protocol.Handlers
/// <param name="cache">Cache for reading chunk data</param>
public void ProcessChunkColumnData(int chunkX, int chunkZ, ushort chunkMask, ushort chunkMask2, bool hasSkyLight, bool chunksContinuous, int currentDimension, Queue<byte> cache)
{
const int chunkColumnSize = 16;
if (protocolversion >= Protocol18Handler.MC_1_9_Version)
{
// 1.9 and above chunk format
// Unloading chunks is handled by a separate packet
for (int chunkY = 0; chunkY < ChunkColumn.ColumnSize; chunkY++)
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
{
if ((chunkMask & (1 << chunkY)) != 0)
{
@ -200,7 +382,7 @@ namespace MinecraftClient.Protocol.Handlers
else
{
//Load chunk data from the server
for (int chunkY = 0; chunkY < ChunkColumn.ColumnSize; chunkY++)
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
{
if ((chunkMask & (1 << chunkY)) != 0)
{
@ -224,7 +406,7 @@ namespace MinecraftClient.Protocol.Handlers
}
//Skip light information
for (int chunkY = 0; chunkY < ChunkColumn.ColumnSize; chunkY++)
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
{
if ((chunkMask & (1 << chunkY)) != 0)
{
@ -258,7 +440,7 @@ namespace MinecraftClient.Protocol.Handlers
//Count chunk sections
int sectionCount = 0;
int addDataSectionCount = 0;
for (int chunkY = 0; chunkY < ChunkColumn.ColumnSize; chunkY++)
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
{
if ((chunkMask & (1 << chunkY)) != 0)
sectionCount++;
@ -286,7 +468,7 @@ namespace MinecraftClient.Protocol.Handlers
dataTypes.ReadData(Chunk.SizeX * Chunk.SizeZ, cache); //Biomes
//Load chunk data
for (int chunkY = 0; chunkY < ChunkColumn.ColumnSize; chunkY++)
for (int chunkY = 0; chunkY < chunkColumnSize; chunkY++)
{
if ((chunkMask & (1 << chunkY)) != 0)
{
@ -307,6 +489,7 @@ namespace MinecraftClient.Protocol.Handlers
}
}
}
handler.GetWorld()[chunkX, chunkZ].FullyLoaded = true;
}
}
}

View file

@ -95,7 +95,7 @@ namespace MinecraftClient.Protocol
/// <param name="data">packet Data</param>
/// <returns>True if message was successfully sent</returns>
bool SendPluginChannelPacket(string channel, byte[] data);
/// <summary>
/// Send Entity Action packet to the server.
/// </summary>
@ -103,7 +103,7 @@ namespace MinecraftClient.Protocol
/// <param name="type">Type of packet to send</param>
/// <returns>True if packet was successfully sent</returns>
bool SendEntityAction(int EntityID, int type);
/// <summary>
/// Send a held item change packet to the server.
/// </summary>
@ -141,7 +141,7 @@ namespace MinecraftClient.Protocol
/// <param name="Z">Z coordinate for "interact at"</param>
/// <returns>True if packet was successfully sent</returns>
bool SendInteractEntity(int EntityID, int type, float X, float Y, float Z);
/// <summary>
/// Send an entity interaction packet to the server.
/// </summary>
@ -164,10 +164,12 @@ namespace MinecraftClient.Protocol
/// </summary>
/// <param name="windowId">Id of the window being clicked</param>
/// <param name="slotId">Id of the clicked slot</param>
/// <param name="buttom">Action to perform</param>
/// <param name="action">Action to perform</param>
/// <param name="item">Item in the clicked slot</param>
/// <param name="changedSlots">Slots that have been changed in this event: List<SlotID, Changed Items> </param>
/// <param name="stateId">Inventory's stateId</param>
/// <returns>True if packet was successfully sent</returns>
bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item);
bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item, List<Tuple<short, Item>> changedSlots, int stateId);
/// <summary>
/// Request Creative Mode item creation into regular/survival Player Inventory
@ -224,7 +226,7 @@ namespace MinecraftClient.Protocol
/// <param name="line4">New line 4</param>
/// <returns>True if packet was succcessfully sent</returns>
bool SendUpdateSign(Location location, string line1, string line2, string line3, string line4);
/// <summary>
/// Update command block
/// </summary>

View file

@ -285,7 +285,8 @@ namespace MinecraftClient.Protocol
/// </summary>
/// <param name="inventoryID">Inventory ID</param>
/// <param name="itemList">Item list</param>
void OnWindowItems(byte inventoryID, Dictionary<int, Item> itemList);
/// <param name="stateId">State ID</param>
void OnWindowItems(byte inventoryID, Dictionary<int, Item> itemList, int stateId);
/// <summary>
/// Called when a single slot has been updated inside an inventory
@ -293,7 +294,8 @@ namespace MinecraftClient.Protocol
/// <param name="inventoryID">Window ID</param>
/// <param name="slotID">Slot ID</param>
/// <param name="item">Item (may be null for empty slot)</param>
void OnSetSlot(byte inventoryID, short slotID, Item item);
/// <param name="stateId">State ID</param>
void OnSetSlot(byte inventoryID, short slotID, Item item, int stateId);
/// <summary>
/// Called when player health or hunger changed.
@ -397,7 +399,7 @@ namespace MinecraftClient.Protocol
/// <param name="action">0 to create/update an item. 1 to remove an item.</param>
/// <param name="objectivename">The name of the objective the score belongs to</param>
/// <param name="value">he score to be displayed next to the entry. Only sent when Action does not equal 1.</param>
void OnUpdateScore(string entityname, byte action, string objectivename, int value);
void OnUpdateScore(string entityname, int action, string objectivename, int value);
/// <summary>
/// Called when tradeList is received from server

View file

@ -44,7 +44,8 @@ mcc.with_forge=, with Forge
mcc.handshake=§8Handshake successful. (Server ID: {0})
mcc.realms_available=You have access to the following Realms worlds
mcc.realms_join=Use realms:<index> as server IP to join a Realms world
mcc.generator.generating=Generating {0} palette using the dataset: {1}
mcc.generator.done=Succesfully generated {0} palette using the dataset: {1}
[debug]
# Messages from MCC Debug Mode
@ -97,6 +98,11 @@ error.realms.access_denied=This Realms world does not exist or access was denied
error.realms.server_unavailable=Realms server may require some time to start up. Please retry again later.
error.realms.server_id=Invalid or unknown Realms server ID.
error.realms.disabled=Trying to join a Realms world but Realms support is disabled in config
error.missing.argument=You are missing argument {0}
error.usage=Usage:
error.generator.invalid=Invalid usage of the generator command!
error.generator.path=Invalid data path provided! (The path either does not exists or you have made a typo)
error.generator.json=The provided path must be a path to a file that is in .json format!
[internal command]
# MCC internal help command
@ -321,11 +327,13 @@ cmd.move.enable=Enabling Terrain and Movements on next server login, respawn or
cmd.move.disable=Disabling Terrain and Movements.
cmd.move.moving=Moving {0}
cmd.move.dir_fail=Cannot move in that direction.
cmd.move.walk=Walking to {0}
cmd.move.walk=Walking from {1} to {0}
cmd.move.fail=Failed to compute path to {0}
cmd.move.suggestforce=Failed to compute a safe path to {0}. Try -f parameter to allow unsafe movements.
cmd.move.gravity.enabled=Gravity is enabled.
cmd.move.gravity.disabled=Gravity is disabled.
cmd.move.chunk_loading_status=Chunk loading status: {0:P} - {1} out of {2} load completed.
cmd.move.chunk_not_loaded=The chunk where the target location resides has not yet been loaded.
# Reco
cmd.reco.desc=restart and reconnect to the server.

View file

@ -327,7 +327,7 @@ namespace MinecraftClient
/// <param name="action">0 to create/update an item. 1 to remove an item.</param>
/// <param name="objectivename">The name of the objective the score belongs to</param>
/// <param name="value">The score to be displayed next to the entry. Only sent when Action does not equal 1.</param>
public virtual void OnUpdateScore(string entityname, byte action, string objectivename, int value) { }
public virtual void OnUpdateScore(string entityname, int action, string objectivename, int value) { }
/// <summary>
/// Called when an inventory/container was updated by server