Merge branch 'general-devel' into tileconv
This commit is contained in:
commit
104598394b
42 changed files with 36285 additions and 21712 deletions
|
|
@ -400,7 +400,7 @@ namespace TShockAPI
|
|||
};
|
||||
PlayerAddBuffWhitelist[BuffID.OnFire3] = new BuffLimit
|
||||
{
|
||||
MaxTicks = 60 * 5,
|
||||
MaxTicks = 60 * 6,
|
||||
CanBeAddedWithoutHostile = false,
|
||||
CanOnlyBeAppliedToSender = false
|
||||
};
|
||||
|
|
@ -416,6 +416,24 @@ namespace TShockAPI
|
|||
CanBeAddedWithoutHostile = false,
|
||||
CanOnlyBeAppliedToSender = false
|
||||
};
|
||||
PlayerAddBuffWhitelist[BuffID.ShadowCandle] = new BuffLimit
|
||||
{
|
||||
MaxTicks = 2,
|
||||
CanBeAddedWithoutHostile = true,
|
||||
CanOnlyBeAppliedToSender = true
|
||||
};
|
||||
PlayerAddBuffWhitelist[BuffID.BrainOfConfusionBuff] = new BuffLimit
|
||||
{
|
||||
MaxTicks = 240,
|
||||
CanBeAddedWithoutHostile = true,
|
||||
CanOnlyBeAppliedToSender = true
|
||||
};
|
||||
PlayerAddBuffWhitelist[BuffID.WindPushed] = new BuffLimit
|
||||
{
|
||||
MaxTicks = 2,
|
||||
CanBeAddedWithoutHostile = true,
|
||||
CanOnlyBeAppliedToSender = true
|
||||
};
|
||||
|
||||
#endregion Whitelist
|
||||
}
|
||||
|
|
@ -674,12 +692,10 @@ namespace TShockAPI
|
|||
}
|
||||
}
|
||||
|
||||
if (action == EditAction.KillTile && !Main.tileCut[tile.type] && !breakableTiles.Contains(tile.type))
|
||||
if (action == EditAction.KillTile && !Main.tileCut[tile.type] && !breakableTiles.Contains(tile.type) && args.Player.RecentFuse == 0)
|
||||
{
|
||||
// TPlayer.mount.Type 8 => Drill Containment Unit.
|
||||
|
||||
// If the tile is an axe tile and they aren't selecting an axe, they're hacking.
|
||||
if (Main.tileAxe[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.axe == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0))
|
||||
if (Main.tileAxe[tile.type] && ((args.Player.TPlayer.mount.Type != MountID.Drill && selectedItem.axe == 0) && !ItemID.Sets.Explosives[selectedItem.netID]))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnTileEdit rejected from (axe) {0} {1} {2}", args.Player.Name, action, editData));
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 4);
|
||||
|
|
@ -687,7 +703,7 @@ namespace TShockAPI
|
|||
return;
|
||||
}
|
||||
// If the tile is a hammer tile and they aren't selecting a hammer, they're hacking.
|
||||
else if (Main.tileHammer[tile.type] && ((args.Player.TPlayer.mount.Type != 8 && selectedItem.hammer == 0) && !ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0))
|
||||
else if (Main.tileHammer[tile.type] && ((args.Player.TPlayer.mount.Type != MountID.Drill && selectedItem.hammer == 0) && !ItemID.Sets.Explosives[selectedItem.netID]))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnTileEdit rejected from (hammer) {0} {1} {2}", args.Player.Name, action, editData));
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 4);
|
||||
|
|
@ -699,11 +715,12 @@ namespace TShockAPI
|
|||
// also add an exception for snake coils, they can be removed when the player places a new one or after x amount of time
|
||||
// If the tile is part of the breakable when placing set, it might be getting broken by a placement.
|
||||
else if (tile.type != TileID.ItemFrame && tile.type != TileID.MysticSnakeRope
|
||||
&& !Main.tileAxe[tile.type] && !Main.tileHammer[tile.type] && tile.wall == 0 &&
|
||||
args.Player.TPlayer.mount.Type != MountID.Drill && selectedItem.pick == 0 &&
|
||||
selectedItem.type != ItemID.GravediggerShovel &&
|
||||
!ItemID.Sets.Explosives[selectedItem.netID] && args.Player.RecentFuse == 0
|
||||
&& !TileID.Sets.BreakableWhenPlacing[tile.type])
|
||||
&& !ItemID.Sets.Explosives[selectedItem.netID]
|
||||
&& !TileID.Sets.BreakableWhenPlacing[tile.type]
|
||||
&& !Main.tileAxe[tile.type] && !Main.tileHammer[tile.type] && tile.wall == 0
|
||||
&& selectedItem.pick == 0 && selectedItem.type != ItemID.GravediggerShovel
|
||||
&& args.Player.TPlayer.mount.Type != MountID.Drill
|
||||
&& args.Player.TPlayer.mount.Type != MountID.DiggingMoleMinecart)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnTileEdit rejected from (pick) {0} {1} {2}", args.Player.Name, action,
|
||||
editData));
|
||||
|
|
@ -764,7 +781,7 @@ namespace TShockAPI
|
|||
if ((action == EditAction.PlaceTile || action == EditAction.ReplaceTile) && editData != selectedItem.createTile)
|
||||
{
|
||||
/// These would get caught up in the below check because Terraria does not set their createTile field.
|
||||
if (selectedItem.netID != ItemID.IceRod && selectedItem.netID != ItemID.DirtBomb && selectedItem.netID != ItemID.StickyBomb)
|
||||
if (selectedItem.netID != ItemID.IceRod && selectedItem.netID != ItemID.DirtBomb && selectedItem.netID != ItemID.StickyBomb && (args.Player.TPlayer.mount.Type != MountID.DiggingMoleMinecart || editData != TileID.MinecartTrack))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnTileEdit rejected from tile placement not matching selected item createTile {0} {1} {2} selectedItemID:{3} createTile:{4}", args.Player.Name, action, editData, selectedItem.netID, selectedItem.createTile));
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 4);
|
||||
|
|
@ -1333,6 +1350,7 @@ namespace TShockAPI
|
|||
|| type == ProjectileID.Dynamite
|
||||
|| type == ProjectileID.StickyBomb
|
||||
|| type == ProjectileID.StickyDynamite
|
||||
|| type == ProjectileID.BombFish
|
||||
|| type == ProjectileID.ScarabBomb
|
||||
|| type == ProjectileID.DirtBomb))
|
||||
{
|
||||
|
|
@ -1704,132 +1722,108 @@ namespace TShockAPI
|
|||
|
||||
// Liquid anti-cheat
|
||||
// Arguably the banned buckets bit should be in the item bans system
|
||||
if (amount != 0)
|
||||
if (amount != 0 && !wasThereABombNearby)
|
||||
{
|
||||
int bucket = -1;
|
||||
int selectedItemType = args.Player.TPlayer.inventory[args.Player.TPlayer.selectedItem].type;
|
||||
if (selectedItemType == ItemID.EmptyBucket)
|
||||
{
|
||||
bucket = 0;
|
||||
}
|
||||
else if (selectedItemType == ItemID.WaterBucket)
|
||||
{
|
||||
bucket = 1;
|
||||
}
|
||||
else if (selectedItemType == ItemID.LavaBucket)
|
||||
{
|
||||
bucket = 2;
|
||||
}
|
||||
else if (selectedItemType == ItemID.HoneyBucket)
|
||||
{
|
||||
bucket = 3;
|
||||
}
|
||||
else if (selectedItemType == ItemID.BottomlessBucket ||
|
||||
selectedItemType == ItemID.SuperAbsorbantSponge)
|
||||
{
|
||||
bucket = 4;
|
||||
}
|
||||
else if (selectedItemType == ItemID.LavaAbsorbantSponge)
|
||||
{
|
||||
bucket = 5;
|
||||
}
|
||||
else if (selectedItemType == ItemID.BottomlessLavaBucket)
|
||||
{
|
||||
bucket = 6;
|
||||
}
|
||||
else if (selectedItemType == ItemID.BottomlessHoneyBucket
|
||||
|| selectedItemType == ItemID.HoneyAbsorbantSponge)
|
||||
{
|
||||
bucket = 7;
|
||||
}
|
||||
else if (selectedItemType == ItemID.BottomlessShimmerBucket)
|
||||
{
|
||||
bucket = 8;
|
||||
}
|
||||
else if (selectedItemType == ItemID.UltraAbsorbantSponge)
|
||||
{
|
||||
bucket = 9;
|
||||
}
|
||||
|
||||
if (!wasThereABombNearby && type == LiquidType.Lava && !(bucket == 2 || bucket == 0 || bucket == 5 || bucket == 6 || bucket == 9))
|
||||
void Reject(string reason)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected bucket check 1 from {0}", args.Player.Name));
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected liquid type {0} from {1} holding {2}", type, args.Player.Name, selectedItemType));
|
||||
args.Player.SendErrorMessage(GetString("You do not have permission to perform this action."));
|
||||
args.Player.Disable(GetString("Spreading lava without holding a lava bucket"), DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.Disable(reason, DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
if (TShock.ItemBans.DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(selectedItemType), args.Player))
|
||||
{
|
||||
Reject(GetString("Using banned {0} to manipulate liquid", Lang.GetItemNameValue(selectedItemType)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasThereABombNearby && type == LiquidType.Lava && TShock.ItemBans.DataModel.ItemIsBanned("Lava Bucket", args.Player))
|
||||
switch (type)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected lava bucket from {0}", args.Player.Name));
|
||||
args.Player.SendErrorMessage(GetString("You do not have permission to perform this action."));
|
||||
args.Player.Disable(GetString("Using banned lava bucket without permissions"), DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
return;
|
||||
case LiquidType.Water:
|
||||
if (TShock.ItemBans.DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(ItemID.WaterBucket), args.Player))
|
||||
{
|
||||
Reject(GetString("Using banned water bucket without permissions"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case LiquidType.Lava:
|
||||
if (TShock.ItemBans.DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(ItemID.LavaBucket), args.Player))
|
||||
{
|
||||
Reject(GetString("Using banned lava bucket without permissions"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case LiquidType.Honey:
|
||||
if (TShock.ItemBans.DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(ItemID.HoneyBucket), args.Player))
|
||||
{
|
||||
Reject(GetString("Using banned honey bucket without permissions"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case LiquidType.Shimmer:
|
||||
if (TShock.ItemBans.DataModel.ItemIsBanned(EnglishLanguage.GetItemNameById(ItemID.BottomlessShimmerBucket), args.Player))
|
||||
{
|
||||
Reject(GetString("Using banned shimmering water bucket without permissions"));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Reject(GetString("Manipulating unknown liquid type"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasThereABombNearby && type == LiquidType.Water && !(bucket == 1 || bucket == 0 || bucket == 4 || bucket == 9))
|
||||
switch (selectedItemType)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected bucket check 2 from {0}", args.Player.Name));
|
||||
args.Player.SendErrorMessage(GetString("You do not have permission to perform this action."));
|
||||
args.Player.Disable(GetString("Spreading water without holding a water bucket"), DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasThereABombNearby && type == LiquidType.Water && TShock.ItemBans.DataModel.ItemIsBanned("Water Bucket", args.Player))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected bucket check 3 from {0}", args.Player.Name));
|
||||
args.Player.SendErrorMessage(GetString("You do not have permission to perform this action."));
|
||||
args.Player.Disable(GetString("Using banned water bucket without permissions"), DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasThereABombNearby && type == LiquidType.Honey && !(bucket == 3 || bucket == 0 || bucket == 7 || bucket == 9))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected bucket check 4 from {0}", args.Player.Name));
|
||||
args.Player.SendErrorMessage(GetString("You do not have permission to perform this action."));
|
||||
args.Player.Disable(GetString("Spreading honey without holding a honey bucket"), DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasThereABombNearby && type == LiquidType.Honey && TShock.ItemBans.DataModel.ItemIsBanned("Honey Bucket", args.Player))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected bucket check 5 from {0}", args.Player.Name));
|
||||
args.Player.SendErrorMessage(GetString("You do not have permission to perform this action."));
|
||||
args.Player.Disable(GetString("Using banned honey bucket without permissions"), DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasThereABombNearby && type == LiquidType.Shimmer && !(bucket == 8 || bucket == 9))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected bucket check 6 from {0}", args.Player.Name));
|
||||
args.Player.SendErrorMessage(GetString("You do not have permission to perform this action."));
|
||||
args.Player.Disable(GetString("Spreading shimmer without holding a shimmer bucket"), DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wasThereABombNearby && type == LiquidType.Shimmer &&
|
||||
TShock.ItemBans.DataModel.ItemIsBanned("Bottomless Shimmer Bucket", args.Player))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnLiquidSet rejected bucket check 7 from {0}", args.Player.Name));
|
||||
args.Player.SendErrorMessage(GetString("You do not have permission to perform this action."));
|
||||
args.Player.Disable(GetString("Using banned bottomless shimmer bucket without permissions"), DisableFlags.WriteToLogAndConsole);
|
||||
args.Player.SendTileSquareCentered(tileX, tileY, 1);
|
||||
args.Handled = true;
|
||||
return;
|
||||
case ItemID.WaterBucket:
|
||||
case ItemID.BottomlessBucket:
|
||||
if (type != LiquidType.Water)
|
||||
{
|
||||
Reject(GetString("Using {0} on non-water", Lang.GetItemNameValue(selectedItemType)));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ItemID.HoneyBucket:
|
||||
case ItemID.HoneyAbsorbantSponge:
|
||||
case ItemID.BottomlessHoneyBucket:
|
||||
if (type != LiquidType.Honey)
|
||||
{
|
||||
Reject(GetString("Using {0} on non-honey", Lang.GetItemNameValue(selectedItemType)));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ItemID.LavaAbsorbantSponge:
|
||||
case ItemID.BottomlessLavaBucket:
|
||||
case ItemID.LavaBucket:
|
||||
if (type != LiquidType.Lava)
|
||||
{
|
||||
Reject(GetString("Using {0} on non-lava", Lang.GetItemNameValue(selectedItemType)));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ItemID.BottomlessShimmerBucket:
|
||||
if (type != LiquidType.Shimmer)
|
||||
{
|
||||
Reject(GetString("Using {0} on non-shimmer", Lang.GetItemNameValue(selectedItemType)));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ItemID.SuperAbsorbantSponge:
|
||||
if (type != LiquidType.Water && type != LiquidType.Shimmer)
|
||||
{
|
||||
Reject(GetString("Using {0} on non-water or shimmer", Lang.GetItemNameValue(selectedItemType)));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ItemID.EmptyBucket:
|
||||
case ItemID.UltraAbsorbantSponge:
|
||||
break;
|
||||
default:
|
||||
Reject(GetString("Using {0} to manipulate unknown liquid {1}", Lang.GetItemNameValue(selectedItemType), type));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1867,41 +1861,57 @@ namespace TShockAPI
|
|||
int type = args.Type;
|
||||
int time = args.Time;
|
||||
|
||||
void Reject(bool shouldResync = true)
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
if (shouldResync)
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, number: id);
|
||||
}
|
||||
|
||||
if (id >= Main.maxPlayers)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected player cap from {0}", args.Player.Name));
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: target ID out of bounds",
|
||||
args.Player.Name, args.Player.Index, type, id, time));
|
||||
Reject(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (TShock.Players[id] == null)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected null check from {0}", args.Player.Name));
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: target is null", args.Player.Name,
|
||||
args.Player.Index, type, id, time));
|
||||
Reject(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (type >= Terraria.ID.BuffID.Count)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected invalid buff type {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, "", id);
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: invalid buff type", args.Player.Name,
|
||||
args.Player.Index, type, id, time));
|
||||
Reject(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Player.IsBeingDisabled())
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected disabled from {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, "", id);
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: sender is being disabled",
|
||||
args.Player.Name, args.Player.Index, type, id, time));
|
||||
Reject();
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Player.IsBouncerThrottled())
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected throttled from {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, "", id);
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: sender is being throttled",
|
||||
args.Player.Name, args.Player.Index, type, id, time));
|
||||
Reject();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1910,41 +1920,46 @@ namespace TShockAPI
|
|||
|
||||
if (!args.Player.IsInRange(targetPlayer.TileX, targetPlayer.TileY, 50))
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected range check from {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, "", id);
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: sender is not in range of target",
|
||||
args.Player.Name, args.Player.Index, type, id, time));
|
||||
Reject();
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffLimit == null)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected non-whitelisted buff {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, "", id);
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: buff is not whitelisted",
|
||||
args.Player.Name, args.Player.Index, type, id, time));
|
||||
Reject();
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffLimit.CanOnlyBeAppliedToSender && id != args.Player.Index)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected applied to non-sender from {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, "", id);
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: buff cannot be applied to non-senders",
|
||||
args.Player.Name, args.Player.Index, type, id, time));
|
||||
Reject();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!buffLimit.CanBeAddedWithoutHostile && !targetPlayer.TPlayer.hostile)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected hostile/pvp from {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, "", id);
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: buff cannot be applied without pvp",
|
||||
args.Player.Name, args.Player.Index, type, id, time));
|
||||
Reject();
|
||||
return;
|
||||
}
|
||||
|
||||
if (time <= 0 || time > buffLimit.MaxTicks)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("Bouncer / OnPlayerBuff rejected time too long from {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.PlayerBuff, "", id);
|
||||
args.Handled = true;
|
||||
TShock.Log.ConsoleDebug(GetString(
|
||||
"Bouncer / OnPlayerBuff rejected {0} ({1}) applying buff {2} to {3} for {4} ticks: buff cannot be applied for that long",
|
||||
args.Player.Name, args.Player.Index, type, id, time));
|
||||
Reject();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ namespace TShockAPI.Configuration
|
|||
[Description("Allows stacks in chests to go beyond the stack limit during world loading.")]
|
||||
public bool IgnoreChestStacksOnLoad = false;
|
||||
|
||||
/// <summary>Allows changing of the default world tile provider.</summary>
|
||||
[Description("Allows changing of the default world tile provider.")]
|
||||
public string WorldTileProvider = "default";
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
|
@ -109,8 +113,8 @@ namespace TShockAPI.Configuration
|
|||
[Description("Enables never ending invasion events. You still need to start the event, such as with the /invade command.")]
|
||||
public bool InfiniteInvasion;
|
||||
|
||||
/// <summary>Sets the PvP mode. Valid types are: "normal", "always", "disabled".</summary>
|
||||
[Description("Sets the PvP mode. Valid types are: \"normal\", \"always\" and \"disabled\".")]
|
||||
/// <summary>Sets the PvP mode. Valid types are: "normal", "always", "pvpwithnoteam", "disabled".</summary>
|
||||
[Description("Sets the PvP mode. Valid types are: \"normal\", \"always\", \"pvpwithnoteam\" and \"disabled\".")]
|
||||
public string PvPMode = "normal";
|
||||
|
||||
/// <summary>Prevents tiles from being placed within SpawnProtectionRadius of the default spawn.</summary>
|
||||
|
|
|
|||
|
|
@ -856,6 +856,14 @@ namespace TShockAPI
|
|||
/// </summary>
|
||||
public int RespawnTimer { get; set; }
|
||||
/// <summary>
|
||||
/// Number Of Deaths PVE
|
||||
/// </summary>
|
||||
public int NumberOfDeathsPVE { get; set; }
|
||||
/// <summary>
|
||||
/// Number Of Deaths PVP
|
||||
/// </summary>
|
||||
public int NumberOfDeathsPVP { get; set; }
|
||||
/// <summary>
|
||||
/// Context of where the player is spawning from.
|
||||
/// </summary>
|
||||
public PlayerSpawnContext SpawnContext { get; set; }
|
||||
|
|
@ -864,7 +872,7 @@ namespace TShockAPI
|
|||
/// PlayerSpawn - When a player spawns
|
||||
/// </summary>
|
||||
public static HandlerList<SpawnEventArgs> PlayerSpawn = new HandlerList<SpawnEventArgs>();
|
||||
private static bool OnPlayerSpawn(TSPlayer player, MemoryStream data, byte pid, int spawnX, int spawnY, int respawnTimer, PlayerSpawnContext spawnContext)
|
||||
private static bool OnPlayerSpawn(TSPlayer player, MemoryStream data, byte pid, int spawnX, int spawnY, int respawnTimer, int numberOfDeathsPVE, int numberOfDeathsPVP, PlayerSpawnContext spawnContext)
|
||||
{
|
||||
if (PlayerSpawn == null)
|
||||
return false;
|
||||
|
|
@ -877,6 +885,8 @@ namespace TShockAPI
|
|||
SpawnX = spawnX,
|
||||
SpawnY = spawnY,
|
||||
RespawnTimer = respawnTimer,
|
||||
NumberOfDeathsPVE = numberOfDeathsPVE,
|
||||
NumberOfDeathsPVP = numberOfDeathsPVP,
|
||||
SpawnContext = spawnContext
|
||||
};
|
||||
PlayerSpawn.Invoke(null, args);
|
||||
|
|
@ -1033,12 +1043,16 @@ namespace TShockAPI
|
|||
/// 0 = Old One's Army, 1 = Granite, 2 = Marble, 3 = Hive, 4 = Gem Cave, 5 = Lihzhard Temple, 6 = Graveyard
|
||||
/// </summary>
|
||||
public BitsByte Zone4 { get; set; }
|
||||
/// <summary>
|
||||
/// 0 = The Aether
|
||||
/// </summary>
|
||||
public BitsByte Zone5 { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// PlayerZone - When the player sends it's zone/biome information to the server
|
||||
/// </summary>
|
||||
public static HandlerList<PlayerZoneEventArgs> PlayerZone = new HandlerList<PlayerZoneEventArgs>();
|
||||
private static bool OnPlayerZone(TSPlayer player, MemoryStream data, byte plr, BitsByte zone1, BitsByte zone2, BitsByte zone3, BitsByte zone4)
|
||||
private static bool OnPlayerZone(TSPlayer player, MemoryStream data, byte plr, BitsByte zone1, BitsByte zone2, BitsByte zone3, BitsByte zone4, BitsByte zone5)
|
||||
{
|
||||
if (PlayerZone == null)
|
||||
return false;
|
||||
|
|
@ -1051,7 +1065,8 @@ namespace TShockAPI
|
|||
Zone1 = zone1,
|
||||
Zone2 = zone2,
|
||||
Zone3 = zone3,
|
||||
Zone4 = zone4
|
||||
Zone4 = zone4,
|
||||
Zone5 = zone5
|
||||
};
|
||||
PlayerZone.Invoke(null, args);
|
||||
return args.Handled;
|
||||
|
|
@ -1519,12 +1534,16 @@ namespace TShockAPI
|
|||
/// Type
|
||||
/// </summary>
|
||||
public byte type { get; set; }
|
||||
/// <summary>
|
||||
/// Paint Coat Tile
|
||||
/// </summary>
|
||||
public byte coatTile { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// NPCStrike - Called when an NPC is attacked
|
||||
/// </summary>
|
||||
public static HandlerList<PaintTileEventArgs> PaintTile = new HandlerList<PaintTileEventArgs>();
|
||||
private static bool OnPaintTile(TSPlayer player, MemoryStream data, Int32 x, Int32 y, byte t)
|
||||
private static bool OnPaintTile(TSPlayer player, MemoryStream data, Int32 x, Int32 y, byte t, byte ct)
|
||||
{
|
||||
if (PaintTile == null)
|
||||
return false;
|
||||
|
|
@ -1535,7 +1554,8 @@ namespace TShockAPI
|
|||
Data = data,
|
||||
X = x,
|
||||
Y = y,
|
||||
type = t
|
||||
type = t,
|
||||
coatTile = ct
|
||||
};
|
||||
PaintTile.Invoke(null, args);
|
||||
return args.Handled;
|
||||
|
|
@ -1558,12 +1578,16 @@ namespace TShockAPI
|
|||
/// Type
|
||||
/// </summary>
|
||||
public byte type { get; set; }
|
||||
/// <summary>
|
||||
/// Paint Coat Wall
|
||||
/// </summary>
|
||||
public byte coatWall { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Called When a wall is painted
|
||||
/// </summary>
|
||||
public static HandlerList<PaintWallEventArgs> PaintWall = new HandlerList<PaintWallEventArgs>();
|
||||
private static bool OnPaintWall(TSPlayer player, MemoryStream data, Int32 x, Int32 y, byte t)
|
||||
private static bool OnPaintWall(TSPlayer player, MemoryStream data, Int32 x, Int32 y, byte t, byte cw)
|
||||
{
|
||||
if (PaintWall == null)
|
||||
return false;
|
||||
|
|
@ -1574,7 +1598,8 @@ namespace TShockAPI
|
|||
Data = data,
|
||||
X = x,
|
||||
Y = y,
|
||||
type = t
|
||||
type = t,
|
||||
coatWall = cw
|
||||
};
|
||||
PaintWall.Invoke(null, args);
|
||||
return args.Handled;
|
||||
|
|
@ -1734,12 +1759,15 @@ namespace TShockAPI
|
|||
/// <summary>Alternate variation of the object placed.</summary>
|
||||
public byte Alternate { get; set; }
|
||||
|
||||
/// <summary>Related to Rubblemaker.</summary>
|
||||
public sbyte Random { get; set; }
|
||||
|
||||
/// <summary>The direction the object was placed.</summary>
|
||||
public bool Direction { get; set; }
|
||||
}
|
||||
/// <summary>Fired when an object is placed in the world.</summary>
|
||||
public static HandlerList<PlaceObjectEventArgs> PlaceObject = new HandlerList<PlaceObjectEventArgs>();
|
||||
private static bool OnPlaceObject(TSPlayer player, MemoryStream data, short x, short y, short type, short style, byte alternate, bool direction)
|
||||
private static bool OnPlaceObject(TSPlayer player, MemoryStream data, short x, short y, short type, short style, byte alternate, sbyte random, bool direction)
|
||||
{
|
||||
if (PlaceObject == null)
|
||||
return false;
|
||||
|
|
@ -1753,6 +1781,7 @@ namespace TShockAPI
|
|||
Type = type,
|
||||
Style = style,
|
||||
Alternate = alternate,
|
||||
Random = random,
|
||||
Direction = direction
|
||||
};
|
||||
|
||||
|
|
@ -1980,6 +2009,10 @@ namespace TShockAPI
|
|||
/// Is the damage critical?
|
||||
/// </summary>
|
||||
public bool Critical { get; set; }
|
||||
/// <summary>
|
||||
/// Cooldown Counter
|
||||
/// </summary>
|
||||
public sbyte CooldownCounter { get; set; }
|
||||
/// <summary>The reason the player took damage and/or died.</summary>
|
||||
public PlayerDeathReason PlayerDeathReason { get; set; }
|
||||
}
|
||||
|
|
@ -1987,7 +2020,7 @@ namespace TShockAPI
|
|||
/// PlayerDamage - Called when a player is damaged
|
||||
/// </summary>
|
||||
public static HandlerList<PlayerDamageEventArgs> PlayerDamage = new HandlerList<PlayerDamageEventArgs>();
|
||||
private static bool OnPlayerDamage(TSPlayer player, MemoryStream data, byte id, byte dir, short dmg, bool pvp, bool crit, PlayerDeathReason playerDeathReason)
|
||||
private static bool OnPlayerDamage(TSPlayer player, MemoryStream data, byte id, byte dir, short dmg, bool pvp, bool crit, sbyte cooldownCounter, PlayerDeathReason playerDeathReason)
|
||||
{
|
||||
if (PlayerDamage == null)
|
||||
return false;
|
||||
|
|
@ -2001,6 +2034,7 @@ namespace TShockAPI
|
|||
Damage = dmg,
|
||||
PVP = pvp,
|
||||
Critical = crit,
|
||||
CooldownCounter = cooldownCounter,
|
||||
PlayerDeathReason = playerDeathReason,
|
||||
};
|
||||
PlayerDamage.Invoke(null, args);
|
||||
|
|
@ -2687,9 +2721,11 @@ namespace TShockAPI
|
|||
short spawnx = args.Data.ReadInt16();
|
||||
short spawny = args.Data.ReadInt16();
|
||||
int respawnTimer = args.Data.ReadInt32();
|
||||
short numberOfDeathsPVE = args.Data.ReadInt16();
|
||||
short numberOfDeathsPVP = args.Data.ReadInt16();
|
||||
PlayerSpawnContext context = (PlayerSpawnContext)args.Data.ReadByte();
|
||||
|
||||
if (OnPlayerSpawn(args.Player, args.Data, player, spawnx, spawny, respawnTimer, context))
|
||||
if (OnPlayerSpawn(args.Player, args.Data, player, spawnx, spawny, respawnTimer, numberOfDeathsPVE, numberOfDeathsPVP, context))
|
||||
return true;
|
||||
|
||||
if ((Main.ServerSideCharacter) && (spawnx == -1 && spawny == -1)) //this means they want to spawn to vanilla spawn
|
||||
|
|
@ -2912,17 +2948,19 @@ namespace TShockAPI
|
|||
Vector2 vel = args.Data.ReadVector2();
|
||||
byte owner = args.Data.ReadInt8();
|
||||
short type = args.Data.ReadInt16();
|
||||
NewProjectileData bits = new NewProjectileData((BitsByte)args.Data.ReadByte());
|
||||
BitsByte bitsByte = (BitsByte)args.Data.ReadByte();
|
||||
BitsByte bitsByte2 = (BitsByte)(bitsByte[2] ? args.Data.ReadByte() : 0);
|
||||
float[] ai = new float[Projectile.maxAI];
|
||||
for (int i = 0; i < Projectile.maxAI; ++i)
|
||||
ai[i] = !bits.AI[i] ? 0.0f : args.Data.ReadSingle();
|
||||
ushort bannerId = bits.HasBannerIdToRespondTo ? args.Data.ReadUInt16() : (ushort)0;
|
||||
short dmg = bits.HasDamage ? args.Data.ReadInt16() : (short)0;
|
||||
float knockback = bits.HasKnockback ? args.Data.ReadSingle() : 0.0f;
|
||||
short origDmg = bits.HasOriginalDamage ? args.Data.ReadInt16() : (short)0;
|
||||
short projUUID = bits.HasUUUID ? args.Data.ReadInt16() : (short)-1;
|
||||
if (projUUID >= 1000)
|
||||
projUUID = -1;
|
||||
for (int i = 0; i < Projectile.maxAI; ++i) ai[i] = 0f;
|
||||
ai[0] = bitsByte[0] ? args.Data.ReadSingle() : 0f;
|
||||
ai[1] = bitsByte[1] ? args.Data.ReadSingle() : 0f;
|
||||
ushort bannerId = (ushort)(bitsByte[3] ? args.Data.ReadUInt16() : 0);
|
||||
short dmg = (short)(bitsByte[4] ? args.Data.ReadInt16() : 0);
|
||||
float knockback = bitsByte[5] ? args.Data.ReadSingle() : 0f;
|
||||
short origDmg = (short)(bitsByte[6] ? args.Data.ReadInt16() : 0);
|
||||
short projUUID = (short)(bitsByte[7] ? args.Data.ReadInt16() : -1);
|
||||
if (projUUID >= 1000) projUUID = -1;
|
||||
ai[2] = (bitsByte2[0] ? args.Data.ReadSingle() : 0f);
|
||||
|
||||
var index = TShock.Utils.SearchProjectile(ident, owner);
|
||||
|
||||
|
|
@ -3054,7 +3092,7 @@ namespace TShockAPI
|
|||
}
|
||||
|
||||
string pvpMode = TShock.Config.Settings.PvPMode.ToLowerInvariant();
|
||||
if (pvpMode == "disabled" || pvpMode == "always" || (DateTime.UtcNow - args.Player.LastPvPTeamChange).TotalSeconds < 5)
|
||||
if (pvpMode == "disabled" || pvpMode == "always" || pvpMode == "pvpwithnoteam" || (DateTime.UtcNow - args.Player.LastPvPTeamChange).TotalSeconds < 5)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandleTogglePvp rejected fastswitch {0}", args.Player.Name));
|
||||
args.Player.SendData(PacketTypes.TogglePvp, "", id);
|
||||
|
|
@ -3150,8 +3188,9 @@ namespace TShockAPI
|
|||
BitsByte zone2 = args.Data.ReadInt8();
|
||||
BitsByte zone3 = args.Data.ReadInt8();
|
||||
BitsByte zone4 = args.Data.ReadInt8();
|
||||
BitsByte zone5 = args.Data.ReadInt8();
|
||||
|
||||
if (OnPlayerZone(args.Player, args.Data, plr, zone1, zone2, zone3, zone4))
|
||||
if (OnPlayerZone(args.Player, args.Data, plr, zone1, zone2, zone3, zone4, zone5))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -3310,7 +3349,8 @@ namespace TShockAPI
|
|||
if (id != args.Player.Index)
|
||||
return true;
|
||||
|
||||
if ((DateTime.UtcNow - args.Player.LastPvPTeamChange).TotalSeconds < 5)
|
||||
string pvpMode = TShock.Config.Settings.PvPMode.ToLowerInvariant();
|
||||
if (pvpMode == "pvpwithnoteam" || (DateTime.UtcNow - args.Player.LastPvPTeamChange).TotalSeconds < 5)
|
||||
{
|
||||
args.Player.SendData(PacketTypes.PlayerTeam, "", id);
|
||||
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandlePlayerTeam rejected team fastswitch {0}", args.Player.Name));
|
||||
|
|
@ -3616,13 +3656,14 @@ namespace TShockAPI
|
|||
var x = args.Data.ReadInt16();
|
||||
var y = args.Data.ReadInt16();
|
||||
var t = args.Data.ReadInt8();
|
||||
var ct = args.Data.ReadInt8();//PaintCoatTile
|
||||
|
||||
if (x < 0 || y < 0 || x >= Main.maxTilesX || y >= Main.maxTilesY || t > Main.numTileColors)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandlePaintTile rejected range check {0}", args.Player.Name));
|
||||
return true;
|
||||
}
|
||||
if (OnPaintTile(args.Player, args.Data, x, y, t))
|
||||
if (OnPaintTile(args.Player, args.Data, x, y, t, ct))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3663,13 +3704,14 @@ namespace TShockAPI
|
|||
var x = args.Data.ReadInt16();
|
||||
var y = args.Data.ReadInt16();
|
||||
var t = args.Data.ReadInt8();
|
||||
var cw = args.Data.ReadInt8();//PaintCoatWall
|
||||
|
||||
if (x < 0 || y < 0 || x >= Main.maxTilesX || y >= Main.maxTilesY || t > Main.numTileColors)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(GetString("GetDataHandlers / HandlePaintWall rejected range check {0}", args.Player.Name));
|
||||
return true;
|
||||
}
|
||||
if (OnPaintWall(args.Player, args.Data, x, y, t))
|
||||
if (OnPaintWall(args.Player, args.Data, x, y, t, cw))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3928,9 +3970,10 @@ namespace TShockAPI
|
|||
short type = args.Data.ReadInt16();
|
||||
short style = args.Data.ReadInt16();
|
||||
byte alternate = args.Data.ReadInt8();
|
||||
sbyte random = (sbyte)args.Data.ReadInt8();
|
||||
bool direction = args.Data.ReadBoolean();
|
||||
|
||||
if (OnPlaceObject(args.Player, args.Data, x, y, type, style, alternate, direction))
|
||||
if (OnPlaceObject(args.Player, args.Data, x, y, type, style, alternate, random, direction))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -4068,7 +4111,7 @@ namespace TShockAPI
|
|||
|
||||
private static bool HandleNpcTeleportPortal(GetDataHandlerArgs args)
|
||||
{
|
||||
var npcIndex = args.Data.ReadByte();
|
||||
var npcIndex = args.Data.ReadUInt16();
|
||||
var portalColorIndex = args.Data.ReadInt16();
|
||||
var newPosition = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
|
||||
var velocity = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
|
||||
|
|
@ -4162,8 +4205,9 @@ namespace TShockAPI
|
|||
var bits = (BitsByte)(args.Data.ReadByte());
|
||||
var crit = bits[0];
|
||||
var pvp = bits[1];
|
||||
var cooldownCounter = (sbyte)args.Data.ReadInt8();
|
||||
|
||||
if (OnPlayerDamage(args.Player, args.Data, id, direction, dmg, pvp, crit, playerDeathReason))
|
||||
if (OnPlayerDamage(args.Player, args.Data, id, direction, dmg, pvp, crit, cooldownCounter, playerDeathReason))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ namespace TShockAPI.Net
|
|||
public short TileX { get; set; }
|
||||
public short TileY { get; set; }
|
||||
public int RespawnTimer { get; set; }
|
||||
public short NumberOfDeathsPVE { get; set; }
|
||||
public short NumberOfDeathsPVP { get; set; }
|
||||
public PlayerSpawnContext PlayerSpawnContext { get; set; }
|
||||
|
||||
public override void Pack(Stream stream)
|
||||
|
|
@ -41,6 +43,8 @@ namespace TShockAPI.Net
|
|||
stream.WriteInt16(TileX);
|
||||
stream.WriteInt16(TileY);
|
||||
stream.WriteInt32(RespawnTimer);
|
||||
stream.WriteInt16(NumberOfDeathsPVE);
|
||||
stream.WriteInt16(NumberOfDeathsPVP);
|
||||
stream.WriteByte((byte) PlayerSpawnContext);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1394,7 +1394,9 @@ namespace TShockAPI
|
|||
/// <param name="tiley">The Y coordinate.</param>
|
||||
/// <param name="context">The PlayerSpawnContext.</param>
|
||||
/// <param name="respawnTimer">The respawn timer, will be Player.respawnTimer if parameter is null.</param>
|
||||
public void Spawn(int tilex, int tiley, PlayerSpawnContext context, int? respawnTimer = null)
|
||||
/// <param name="numberOfDeathsPVE">The number of deaths PVE, will be TPlayer.numberOfDeathsPVE if parameter is null.</param>
|
||||
/// <param name="numberOfDeathsPVP">The number of deaths PVP, will be TPlayer.numberOfDeathsPVP if parameter is null.</param>
|
||||
public void Spawn(int tilex, int tiley, PlayerSpawnContext context, int? respawnTimer = null, short? numberOfDeathsPVE = null, short? numberOfDeathsPVP = null)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
|
|
@ -1404,6 +1406,8 @@ namespace TShockAPI
|
|||
TileX = (short)tilex,
|
||||
TileY = (short)tiley,
|
||||
RespawnTimer = respawnTimer ?? TShock.Players[Index].RespawnTimer * 60,
|
||||
NumberOfDeathsPVE = numberOfDeathsPVE ?? (short)TPlayer.numberOfDeathsPVE,
|
||||
NumberOfDeathsPVP = numberOfDeathsPVP ?? (short)TPlayer.numberOfDeathsPVP,
|
||||
PlayerSpawnContext = context,
|
||||
};
|
||||
msg.PackFull(ms);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ using TShockAPI.Localization;
|
|||
using TShockAPI.Configuration;
|
||||
using Terraria.GameContent.Creative;
|
||||
using System.Runtime.InteropServices;
|
||||
using MonoMod.Cil;
|
||||
using Terraria.Achievements;
|
||||
using Terraria.Initializers;
|
||||
using Terraria.UI.Chat;
|
||||
using TShockAPI.Modules;
|
||||
|
||||
namespace TShockAPI
|
||||
|
|
@ -383,6 +387,19 @@ namespace TShockAPI
|
|||
if (Config.Settings.EnableGeoIP && File.Exists(geoippath))
|
||||
Geo = new GeoIPCountry(geoippath);
|
||||
|
||||
// check if a custom tile provider is to be used
|
||||
switch(Config.Settings.WorldTileProvider?.ToLower())
|
||||
{
|
||||
case "heaptile":
|
||||
Log.ConsoleInfo(GetString($"Using {nameof(HeapTile)} for tile implementation"), TraceLevel.Info);
|
||||
Main.tile = new TileProvider();
|
||||
break;
|
||||
case "constileation":
|
||||
Log.ConsoleInfo(GetString($"Using {nameof(ConstileationProvider)} for tile implementation"), TraceLevel.Info);
|
||||
Main.tile = new ConstileationProvider();
|
||||
break;
|
||||
}
|
||||
|
||||
Log.ConsoleInfo(GetString("TShock {0} ({1}) now running.", Version, VersionCodename));
|
||||
|
||||
ServerApi.Hooks.GamePostInitialize.Register(this, OnPostInit);
|
||||
|
|
@ -416,6 +433,33 @@ namespace TShockAPI
|
|||
|
||||
EnglishLanguage.Initialize();
|
||||
|
||||
// The AchievementTagHandler expects Main.Achievements to be non-null, which is not normally the case on dedicated servers.
|
||||
// When trying to parse an achievement chat tag, it will instead throw.
|
||||
// The tag is parsed when calling ChatManager.ParseMessage, which is used in TShock when writing chat messages to the
|
||||
// console. Our OnChat handler uses Utils.Broadcast, which will send the message to all connected clients, write the message
|
||||
// to the console and the log. Due to the order of execution, the message ends up being sent to all connected clients, but
|
||||
// throws whilst trying to write to the console, and never gets written to the log.
|
||||
// To solve the issue, we make achievements available on the server, allowing the tag handler to work as expected, and
|
||||
// even allowing the localization of achievement names to appear in the console.
|
||||
|
||||
if (Game != null)
|
||||
{
|
||||
// Initialize the AchievementManager, which is normally only done on clients.
|
||||
Game._achievements = new AchievementManager();
|
||||
|
||||
IL.Terraria.Initializers.AchievementInitializer.Load += OnAchievementInitializerLoad;
|
||||
|
||||
// Actually call AchievementInitializer.Load, which is also normally only done on clients.
|
||||
AchievementInitializer.Load();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we don't have a Game instance, then we'll just remove the achievement tag handler entirely. This will cause the
|
||||
// raw tag to just be used instead (and not be localized), but still avoid all the issues outlined above.
|
||||
ChatManager._handlers.Remove("a", out _);
|
||||
ChatManager._handlers.Remove("achievement", out _);
|
||||
}
|
||||
|
||||
ModuleManager.Initialise(new object[] { this });
|
||||
|
||||
if (Config.Settings.RestApiEnabled)
|
||||
|
|
@ -452,6 +496,13 @@ namespace TShockAPI
|
|||
}
|
||||
}
|
||||
|
||||
private static void OnAchievementInitializerLoad(ILContext il)
|
||||
{
|
||||
// Modify AchievementInitializer.Load to remove the Main.netMode == 2 check (occupies the first 4 IL instructions)
|
||||
for (var i = 0; i < 4; i++)
|
||||
il.Body.Instructions.RemoveAt(0);
|
||||
}
|
||||
|
||||
protected void CrashReporter_HeapshotRequesting(object sender, EventArgs e)
|
||||
{
|
||||
foreach (TSPlayer player in TShock.Players)
|
||||
|
|
@ -473,6 +524,8 @@ namespace TShockAPI
|
|||
}
|
||||
SaveManager.Instance.Dispose();
|
||||
|
||||
IL.Terraria.Initializers.AchievementInitializer.Load -= OnAchievementInitializerLoad;
|
||||
|
||||
ModuleManager.Dispose();
|
||||
|
||||
ServerApi.Hooks.GamePostInitialize.Deregister(this, OnPostInit);
|
||||
|
|
@ -1663,7 +1716,7 @@ namespace TShockAPI
|
|||
player.SendFileTextAsMessage(FileTools.MotdPath);
|
||||
|
||||
string pvpMode = Config.Settings.PvPMode.ToLowerInvariant();
|
||||
if (pvpMode == "always")
|
||||
if (pvpMode == "always" || pvpMode == "pvpwithnoteam")
|
||||
{
|
||||
player.TPlayer.hostile = true;
|
||||
player.SendData(PacketTypes.TogglePvp, "", player.Index);
|
||||
|
|
|
|||
|
|
@ -290,9 +290,15 @@ namespace TShockAPI
|
|||
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return new List<Item> { GetItemById(i) };
|
||||
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
startswith.Add(i);
|
||||
else if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
contains.Add(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
currentName = EnglishLanguage.GetItemNameById(i);
|
||||
if (!string.IsNullOrEmpty(currentName))
|
||||
|
|
@ -300,9 +306,15 @@ namespace TShockAPI
|
|||
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return new List<Item> { GetItemById(i) };
|
||||
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
startswith.Add(i);
|
||||
else if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
contains.Add(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,9 +389,15 @@ namespace TShockAPI
|
|||
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return new List<NPC> { GetNPCById(i) };
|
||||
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
startswith.Add(i);
|
||||
else if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
contains.Add(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
currentName = EnglishLanguage.GetNpcNameById(i);
|
||||
if (!string.IsNullOrEmpty(currentName))
|
||||
|
|
@ -387,9 +405,15 @@ namespace TShockAPI
|
|||
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return new List<NPC> { GetNPCById(i) };
|
||||
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
startswith.Add(i);
|
||||
else if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
contains.Add(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -435,9 +459,15 @@ namespace TShockAPI
|
|||
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return new List<int> { i };
|
||||
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
startswith.Add(i);
|
||||
else if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
contains.Add(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
currentName = EnglishLanguage.GetBuffNameById(i);
|
||||
if (!string.IsNullOrWhiteSpace(currentName))
|
||||
|
|
@ -445,9 +475,15 @@ namespace TShockAPI
|
|||
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return new List<int> { i };
|
||||
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
startswith.Add(i);
|
||||
else if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
contains.Add(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -483,9 +519,15 @@ namespace TShockAPI
|
|||
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return new List<int> { i };
|
||||
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
startswith.Add(i);
|
||||
else if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
contains.Add(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
currentName = EnglishLanguage.GetPrefixById(i);
|
||||
if (!string.IsNullOrWhiteSpace(currentName))
|
||||
|
|
@ -493,9 +535,15 @@ namespace TShockAPI
|
|||
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
return new List<int> { i };
|
||||
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
startswith.Add(i);
|
||||
else if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
continue;
|
||||
}
|
||||
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
contains.Add(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue