public static void SpawnEffectFor(Player p, string effectName, float x, float y, float z, float originX, float originY, float originZ) { EffectConfig effect; if (!effectAtEffectName.TryGetValue(effectName, out effect)) { p.Message("%WCould not find effect named \"{0}\" !", effectName); return; } if (!p.Supports(CpeExt.CustomParticles)) { return; } p.Send(Packet.SpawnEffect(effect.ID, x, y - effect.offset, z, originX, originY - effect.offset, originZ)); }
unsafe static void UpdatePosition(Player p) { Player[] players = PlayerInfo.Online.Items; byte * src = stackalloc byte[16 * 256]; // 16 = size of absolute update, with extended positions byte * ptr = src; foreach (Player pl in players) { if (p == pl || p.level != pl.level || !p.CanSeeEntity(pl)) { continue; } Orientation rot = pl.Rot; byte pitch = rot.HeadX; if (Server.flipHead || p.flipHead) { pitch = FlippedPitch(pitch); } // flip head when infected, but doesn't support model if (!p.hasChangeModel) { ZSData data = ZSGame.TryGet(p); if (data != null && data.Infected) { pitch = FlippedPitch(pitch); } } rot.HeadX = pitch; Entities.GetPositionPacket(ref ptr, pl.id, pl.hasExtPositions, p.hasExtPositions, pl.tempPos, pl.lastPos, rot, pl.lastRot); } int count = (int)(ptr - src); if (count == 0) { return; } byte[] packet = new byte[count]; for (int i = 0; i < packet.Length; i++) { packet[i] = src[i]; } p.Send(packet); }
static void SendModelScale(Player pl, byte id, EntityProp axis, float value, float max) { if (value == 0) { return; } value = Math.Min(value, max); int packed = (int)(value * 1000); if (packed == 0) { return; } pl.Send(Packet.EntityProperty(id, axis, packed)); }
static void SendDefineBlockExt(Player p, BlockDefinition def, bool uniqueSideTexs) { byte[] buffer = new byte[uniqueSideTexs ? 88 : 85]; int index = 0; buffer[index++] = Opcode.CpeDefineBlockExt; MakeDefineBlockStart(def, buffer, ref index, uniqueSideTexs); buffer[index++] = def.MinX; buffer[index++] = def.MinZ; buffer[index++] = def.MinY; buffer[index++] = def.MaxX; buffer[index++] = def.MaxZ; buffer[index++] = def.MaxY; MakeDefineBlockEnd(def, ref index, buffer); p.Send(buffer); }
static void SendModel(Player pl, byte id, string model) { BlockID raw; if (BlockID.TryParse(model, out raw) && raw > pl.MaxRawBlock) { BlockID block = Block.FromRaw(raw); if (block >= Block.ExtendedCount) { model = "humanoid"; // invalid block ids } else { model = pl.ConvertBlock(block).ToString(); } } pl.Send(Packet.ChangeModel(id, model, pl.hasCP437)); }
static void UndefineModel(Player p, string name) { lock (ModelNameToIdForPlayer) { bool hasV1 = p.Supports(CpeExt.CustomModels, 1); bool hasV2 = p.Supports(CpeExt.CustomModels, 2); if (hasV1 || hasV2) { var modelId = GetModelId(p, name).Value; Debug("UndefineModel {0} {1} {2}", modelId, p.name, name); byte[] modelPacket = Packet.UndefineModel(modelId); p.Send(modelPacket); var modelNameToId = ModelNameToIdForPlayer[p.name]; modelNameToId.TryRemove(name, out _); } } }
/// <summary> Adds the given player to that player's tab list (if their client supports it). </summary> public static void Add(Player dst, Player p, byte id) { if (!dst.hasExtList) { return; } byte grpPerm = (byte)(offset - p.Rank); if (!ServerConfig.TablistRankSorted) { grpPerm = 0; } string name, group; GetEntry(p, dst, out name, out group); name = Colors.Cleanup(name, dst.hasTextColors); group = Colors.Cleanup(group, dst.hasTextColors); dst.Send(Packet.ExtAddPlayerName(id, p.truename, name, group, grpPerm, dst.hasCP437)); }
public static void HitPlayer(PlayerBot bot, Player p, Orientation rot) { // Send player backwards if hit // Code "borrowed" from PvP plugin int srcHeight = ModelInfo.CalcEyeHeight(bot); int dstHeight = ModelInfo.CalcEyeHeight(p); int dx2 = bot.Pos.X - p.Pos.X, dy2 = (bot.Pos.Y + srcHeight) - (p.Pos.Y + dstHeight), dz2 = bot.Pos.Z - p.Pos.Z; Vec3F32 dir2 = new Vec3F32(dx2, dy2, dz2); if (dir2.Length > 0) { dir2 = Vec3F32.Normalise(dir2); } float mult = 1 / ModelInfo.GetRawScale(p.Model); float plScale = ModelInfo.GetRawScale(p.Model); float VelocityY = 1.0117f * mult; if (dir2.Length <= 0) { VelocityY = 0; } if (p.Supports(CpeExt.VelocityControl)) { // Intensity of force is in part determined by model scale p.Send(Packet.VelocityControl((-dir2.X * mult) * 0.57f, VelocityY, (-dir2.Z * mult) * 0.57f, 0, 1, 0)); } // If we are very close to a player, switch from trying to look // at them to just facing the opposite direction to them rot.RotY = (byte)(p.Rot.RotY + 128); bot.Rot = rot; }
static void SpawnRaw(Player dst, byte id, Entity e, Position pos, Orientation rot, string skin, string name, string model) { // NOTE: Fix for standard clients if (id == Entities.SelfID) { pos.Y -= 22; } name = Colors.Cleanup(name, dst.hasTextColors); if (dst.Supports(CpeExt.ExtPlayerList, 2)) { dst.Send(Packet.ExtAddEntity2(id, skin, name, pos, rot, dst.hasCP437, dst.hasExtPositions)); } else if (dst.hasExtList) { dst.Send(Packet.ExtAddEntity(id, skin, name, dst.hasCP437)); dst.Send(Packet.Teleport(id, pos, rot, dst.hasExtPositions)); } else { dst.Send(Packet.AddEntity(id, name, pos, rot, dst.hasCP437, dst.hasExtPositions)); } if (dst.hasChangeModel) { OnSendingModelEvent.Call(e, ref model, dst); if (!model.CaselessEq("humanoid")) { SendModel(dst, id, model); } } if (dst.Supports(CpeExt.EntityProperty)) { dst.Send(Packet.EntityProperty(id, EntityProp.RotX, Orientation.PackedToDegrees(rot.RotX))); dst.Send(Packet.EntityProperty(id, EntityProp.RotZ, Orientation.PackedToDegrees(rot.RotZ))); SendModelScales(dst, id, e); } }
internal unsafe static void SendLevelInventoryOrder(Player pl) { BlockDefinition[] defs = pl.level.CustomBlockDefs; int count = pl.MaxRawBlock + 1; int *order_to_blocks = stackalloc int[Block.ExtendedCount]; int *block_to_orders = stackalloc int[Block.ExtendedCount]; for (int b = 0; b < Block.ExtendedCount; b++) { order_to_blocks[b] = -1; block_to_orders[b] = -1; } // Fill slots with explicit order for (int i = 0; i < defs.Length; i++) { BlockDefinition def = defs[i]; if (def == null || def.RawID > pl.MaxRawBlock) { continue; } if (def.InventoryOrder == -1) { continue; } if (def.InventoryOrder != 0) { if (order_to_blocks[def.InventoryOrder] != -1) { continue; } order_to_blocks[def.InventoryOrder] = def.RawID; } block_to_orders[def.RawID] = def.InventoryOrder; } // Put blocks into their default slot if slot is unused for (int i = 0; i < defs.Length; i++) { BlockDefinition def = defs[i]; int raw = def != null ? def.RawID : i; if (raw > pl.MaxRawBlock || (def == null && raw >= Block.CpeCount)) { continue; } if (def != null && def.InventoryOrder >= 0) { continue; } if (order_to_blocks[raw] == -1) { order_to_blocks[raw] = raw; block_to_orders[raw] = raw; } } // Push blocks whose slots conflict with other blocks into free slots at end for (int i = defs.Length - 1; i >= 0; i--) { BlockDefinition def = defs[i]; int raw = def != null ? def.RawID : i; if (raw > pl.MaxRawBlock || (def == null && raw >= Block.CpeCount)) { continue; } if (block_to_orders[raw] != -1) { continue; } for (int slot = count - 1; slot >= 1; slot--) { if (order_to_blocks[slot] != -1) { continue; } block_to_orders[raw] = slot; order_to_blocks[slot] = raw; break; } } for (int raw = 0; raw < count; raw++) { int order = block_to_orders[raw]; if (order == -1) { order = 0; } BlockDefinition def = defs[Block.FromRaw((BlockID)raw)]; if (def == null && raw >= Block.CpeCount) { continue; } // Special case, don't want 255 getting hidden by default if (raw == 255 && def.InventoryOrder == -1) { continue; } pl.Send(Packet.SetInventoryOrder((BlockID)raw, (BlockID)order, pl.hasExtBlocks)); } }