/// <summary> /// Expands the Composite Texture to a texture atlas friendly version and populates the Baked field /// </summary> public void LoadAlternates(IAssetManager assetManager, ILogger logger) { if (Base.Path.EndsWith("*")) { List <IAsset> assets = assetManager.GetMany("shapes/" + Base.Path.Substring(0, Base.Path.Length - 1), Base.Domain); if (assets.Count == 0) { logger.Warning("Could not find any variants for shape {0}, will use standard cube shape.", Base.Path); Base = new AssetLocation("block/basic/cube"); } if (assets.Count == 1) { Base = assets[0].Location.CopyWithPath(assets[0].Location.Path.Substring("shapes/".Length)); Base.RemoveEnding(); } if (assets.Count > 1) { int origLength = (Alternates == null ? 0 : Alternates.Length); CompositeShape[] alternates = new CompositeShape[origLength + assets.Count]; if (Alternates != null) { Array.Copy(Alternates, alternates, Alternates.Length); } int i = 0; foreach (IAsset asset in assets) { AssetLocation newLocation = asset.Location.CopyWithPath(asset.Location.Path.Substring("shapes/".Length)); newLocation.RemoveEnding(); if (i == 0) { Base = newLocation.Clone(); } alternates[origLength + i] = new CompositeShape() { Base = newLocation, rotateX = rotateX, rotateY = rotateY, rotateZ = rotateZ }; i++; } Alternates = alternates; } } if (Alternates != null) { BakedAlternates = new CompositeShape[Alternates.Length + 1]; BakedAlternates[0] = this.Clone(); BakedAlternates[0].Alternates = null; for (int i = 0; i < Alternates.Length; i++) { BakedAlternates[i + 1] = Alternates[i].Clone(); if (BakedAlternates[i + 1].Base == null) { BakedAlternates[i + 1].Base = Base.Clone(); } if (BakedAlternates[i + 1].QuantityElements == null) { BakedAlternates[i + 1].QuantityElements = QuantityElements; } if (BakedAlternates[i + 1].SelectiveElements == null) { BakedAlternates[i + 1].SelectiveElements = SelectiveElements; } } } }
private void updateEyeHeight(float dt) { IPlayer player = World.PlayerByUid(PlayerUID); PrevFrameCanStandUp = true; if (player != null && player?.WorldData?.CurrentGameMode != EnumGameMode.Spectator) { PrevFrameCanStandUp = !servercontrols.Sneak && canStandUp(); bool moving = (servercontrols.TriesToMove && SidedPos.Motion.LengthSq() > 0.00001) && !servercontrols.NoClip && !servercontrols.FlyMode && OnGround; double newEyeheight = Properties.EyeHeight; if (player.ImmersiveFpMode) { updateLocalEyePosImmersiveFpMode(); newEyeheight = LocalEyePos.Y; } else { double newModelHeight = Properties.CollisionBoxSize.Y; if (servercontrols.FloorSitting) { newEyeheight *= 0.5f; newModelHeight *= 0.55f; } else if ((servercontrols.Sneak || !PrevFrameCanStandUp) && !servercontrols.IsClimbing && !servercontrols.IsFlying) { newEyeheight *= 0.8f; newModelHeight *= 0.8f; } else if (!Alive) { newEyeheight *= 0.25f; newModelHeight *= 0.25f; } double diff = (newEyeheight - LocalEyePos.Y) * 5 * dt; LocalEyePos.Y = diff > 0 ? Math.Min(LocalEyePos.Y + diff, newEyeheight) : Math.Max(LocalEyePos.Y + diff, newEyeheight); diff = (newModelHeight - OriginSelectionBox.Y2) * 5 * dt; OriginSelectionBox.Y2 = SelectionBox.Y2 = (float)(diff > 0 ? Math.Min(SelectionBox.Y2 + diff, newModelHeight) : Math.Max(SelectionBox.Y2 + diff, newModelHeight)); diff = (newModelHeight - OriginCollisionBox.Y2) * 5 * dt; OriginCollisionBox.Y2 = CollisionBox.Y2 = (float)(diff > 0 ? Math.Min(CollisionBox.Y2 + diff, newModelHeight) : Math.Max(CollisionBox.Y2 + diff, newModelHeight)); LocalEyePos.X = 0; LocalEyePos.Z = 0; if (MountedOn?.SuggestedAnimation == "sleep") { LocalEyePos.Y = 0.3; } } double frequency = dt * servercontrols.MovespeedMultiplier * GetWalkSpeedMultiplier(0.3) * (servercontrols.Sprint ? 0.9 : 1.2) * (servercontrols.Sneak ? 1.2f : 1); walkCounter = moving ? walkCounter + frequency : 0; walkCounter = walkCounter % GameMath.TWOPI; double sneakDiv = (servercontrols.Sneak ? 3 : 1.8); double amplitude = (FeetInLiquid ? 0.8 : 1 + (servercontrols.Sprint ? 0.07 : 0)) / (3 * sneakDiv); double offset = -0.2 / sneakDiv; double stepHeight = -Math.Max(0, Math.Abs(GameMath.Sin(5.5f * walkCounter) * amplitude) + offset); if (World.Side == EnumAppSide.Client) { ICoreClientAPI capi = World.Api as ICoreClientAPI; if (capi.Settings.Bool["viewBobbing"] && capi.Render.CameraType == EnumCameraMode.FirstPerson) { LocalEyePos.Y += stepHeight / 3f * dt * 60f; } } if (moving) { if (stepHeight > prevStepHeight) { if (direction == -1) { float volume = controls.Sneak ? 0.5f : 1f; EntityPos pos = SidedPos; int blockIdUnder = BlockUnderPlayer(pos); int blockIdInside = BlockInsidePlayer(pos); AssetLocation soundwalk = World.Blocks[blockIdUnder].GetSounds(Api.World.BlockAccessor, new BlockPos((int)pos.X, (int)(pos.Y - 0.1f), (int)pos.Z))?.Walk; AssetLocation soundinside = World.Blocks[blockIdInside].GetSounds(Api.World.BlockAccessor, new BlockPos((int)pos.X, (int)(pos.Y + 0.1f), (int)pos.Z))?.Inside; if (!Swimming && soundwalk != null) { if (blockIdInside != blockIdUnder && soundinside != null) { World.PlaySoundAt(soundwalk, this, player, true, 12, volume * 0.5f); World.PlaySoundAt(soundinside, this, player, true, 12, volume); } else { World.PlaySoundAt(soundwalk, this, player, true, 12, volume); } OnFootStep?.Invoke(); } } direction = 1; } else { direction = -1; } } prevStepHeight = stepHeight; } }
protected Shape addGearToShape(ItemSlot slot, Shape entityShape, string shapePathForLogging) { if (slot.Empty) { return(entityShape); } ItemStack stack = slot.Itemstack; JsonObject attrObj = stack.Collectible.Attributes; string[] disableElements = attrObj?["disableElements"]?.AsArray <string>(null); if (disableElements != null) { foreach (var val in disableElements) { entityShape.RemoveElementByName(val); } } if (attrObj?["wearableAttachment"].Exists != true) { return(entityShape); } CompositeShape compArmorShape = !attrObj["attachShape"].Exists ? (stack.Class == EnumItemClass.Item ? stack.Item.Shape : stack.Block.Shape) : attrObj["attachShape"].AsObject <CompositeShape>(null, stack.Collectible.Code.Domain); AssetLocation shapePath = shapePath = compArmorShape.Base.CopyWithPath("shapes/" + compArmorShape.Base.Path + ".json"); IAsset asset = Api.Assets.TryGet(shapePath); if (asset == null) { Api.World.Logger.Warning("Entity armor shape {0} defined in {1} {2} not found, was supposed to be at {3}. Armor piece will be invisible.", compArmorShape.Base, stack.Class, stack.Collectible.Code, shapePath); return(null); } Shape armorShape; try { armorShape = asset.ToObject <Shape>(); } catch (Exception e) { Api.World.Logger.Warning("Exception thrown when trying to load entity armor shape {0} defined in {1} {2}. Armor piece will be invisible. Exception: {3}", compArmorShape.Base, slot.Itemstack.Class, slot.Itemstack.Collectible.Code, e); return(null); } bool added = false; foreach (var val in armorShape.Elements) { ShapeElement elem; if (val.StepParentName != null) { elem = entityShape.GetElementByName(val.StepParentName, StringComparison.InvariantCultureIgnoreCase); if (elem == null) { Api.World.Logger.Warning("Entity armor shape {0} defined in {1} {2} requires step parent element with name {3}, but no such element was found in shape {4}. Will not be visible.", compArmorShape.Base, slot.Itemstack.Class, slot.Itemstack.Collectible.Code, val.StepParentName, shapePathForLogging); continue; } } else { Api.World.Logger.Warning("Entity armor shape element {0} in shape {1} defined in {2} {3} did not define a step parent element. Will not be visible.", val.Name, compArmorShape.Base, slot.Itemstack.Class, slot.Itemstack.Collectible.Code); continue; } if (elem.Children == null) { elem.Children = new ShapeElement[] { val }; } else { elem.Children = elem.Children.Append(val); } val.SetJointIdRecursive(elem.JointId); val.WalkRecursive((el) => { foreach (var face in el.Faces) { face.Value.Texture = "#" + stack.Collectible.Code + "-" + face.Value.Texture.TrimStart('#'); } }); added = true; } if (added && armorShape.Textures != null) { Dictionary <string, AssetLocation> newdict = new Dictionary <string, AssetLocation>(); foreach (var val in armorShape.Textures) { newdict[stack.Collectible.Code + "-" + val.Key] = val.Value; } // Item overrides var collDict = stack.Class == EnumItemClass.Block ? stack.Block.Textures : stack.Item.Textures; foreach (var val in collDict) { newdict[stack.Collectible.Code + "-" + val.Key] = val.Value.Base; } armorShape.Textures = newdict; foreach (var val in armorShape.Textures) { CompositeTexture ctex = new CompositeTexture() { Base = val.Value }; entityShape.TextureSizes[val.Key] = new int[] { armorShape.TextureWidth, armorShape.TextureHeight }; AssetLocation armorTexLoc = val.Value; // Weird backreference to the shaperenderer. Should be refactored. var texturesByLoc = extraTextureByLocation; var texturesByName = extraTexturesByTextureName; BakedCompositeTexture bakedCtex; ICoreClientAPI capi = Api as ICoreClientAPI; if (!texturesByLoc.TryGetValue(armorTexLoc, out bakedCtex)) { int textureSubId = 0; TextureAtlasPosition texpos; IAsset texAsset = Api.Assets.TryGet(val.Value.Clone().WithPathPrefixOnce("textures/").WithPathAppendixOnce(".png")); if (texAsset != null) { BitmapRef bmp = texAsset.ToBitmap(capi); capi.EntityTextureAtlas.InsertTexture(bmp, out textureSubId, out texpos); } else { capi.World.Logger.Warning("Entity armor shape {0} defined texture {1}, no such texture found.", shapePath, val.Value); } ctex.Baked = new BakedCompositeTexture() { BakedName = val.Value, TextureSubId = textureSubId }; texturesByName[val.Key] = ctex; texturesByLoc[armorTexLoc] = ctex.Baked; } else { ctex.Baked = bakedCtex; texturesByName[val.Key] = ctex; } } foreach (var val in armorShape.TextureSizes) { entityShape.TextureSizes[val.Key] = val.Value; } } return(entityShape); }
/// <summary> /// /// </summary> /// <param name="code">Any unique Identifier</param> /// <param name="cshape"></param> /// <param name="entityShape"></param> /// <param name="shapePathForLogging"></param> /// <param name="disableElements"></param> /// <returns></returns> protected Shape addGearToShape(string code, CompositeShape cshape, Shape entityShape, string shapePathForLogging, string[] disableElements = null, Dictionary <string, AssetLocation> textureOverrides = null) { AssetLocation shapePath = shapePath = cshape.Base.CopyWithPath("shapes/" + cshape.Base.Path + ".json"); if (disableElements != null) { foreach (var val in disableElements) { entityShape.RemoveElementByName(val); } } IAsset asset = Api.Assets.TryGet(shapePath); if (asset == null) { Api.World.Logger.Warning("Compositshape {0} (code: {2}) defined but not found, was supposed to be at {1}. Part will be invisible.", cshape.Base, shapePath, code); return(null); } Shape armorShape; try { armorShape = asset.ToObject <Shape>(); } catch (Exception e) { Api.World.Logger.Warning("Exception thrown when trying to load gear shape {0} (code: {2}) . Will be invisible. Exception: {1}", cshape.Base, e, code); return(null); } bool added = applyStepParents(null, armorShape.Elements, entityShape, code, cshape, shapePathForLogging); if (added && armorShape.Textures != null) { Dictionary <string, AssetLocation> newdict = new Dictionary <string, AssetLocation>(); foreach (var val in armorShape.Textures) { newdict[code + "-" + val.Key] = val.Value; } // Texture overrides if (textureOverrides != null) { foreach (var val in textureOverrides) { newdict[code + "-" + val.Key] = val.Value; } } armorShape.Textures = newdict; foreach (var val in armorShape.Textures) { CompositeTexture ctex = new CompositeTexture() { Base = val.Value }; entityShape.TextureSizes[val.Key] = new int[] { armorShape.TextureWidth, armorShape.TextureHeight }; AssetLocation armorTexLoc = val.Value; // Weird backreference to the shaperenderer. Should be refactored. var texturesByLoc = extraTextureByLocation; var texturesByName = extraTexturesByTextureName; BakedCompositeTexture bakedCtex; ICoreClientAPI capi = Api as ICoreClientAPI; if (!texturesByLoc.TryGetValue(armorTexLoc, out bakedCtex)) { int textureSubId = 0; TextureAtlasPosition texpos; IAsset texAsset = Api.Assets.TryGet(val.Value.Clone().WithPathPrefixOnce("textures/").WithPathAppendixOnce(".png")); if (texAsset != null) { BitmapRef bmp = texAsset.ToBitmap(capi); capi.EntityTextureAtlas.InsertTexture(bmp, out textureSubId, out texpos); } else { capi.World.Logger.Warning("Entity armor shape {0} defined texture {1}, not no such texture found.", shapePath, val.Value); } ctex.Baked = new BakedCompositeTexture() { BakedName = val.Value, TextureSubId = textureSubId }; texturesByName[val.Key] = ctex; texturesByLoc[armorTexLoc] = ctex.Baked; } else { ctex.Baked = bakedCtex; texturesByName[val.Key] = ctex; } } foreach (var val in armorShape.TextureSizes) { entityShape.TextureSizes[val.Key] = val.Value; } } return(entityShape); }
/// <summary> /// Returns true if given wildcard matches the blocks/items code. E.g. water-* will match all water blocks /// </summary> /// <param name="wildCard"></param> /// <returns></returns> public bool WildCardMatch(AssetLocation wildCard) { return(Code != null && WildcardUtil.Match(wildCard, Code)); }