diff --git a/Minecraft.Server.FourKit/Block/Block.cs b/Minecraft.Server.FourKit/Block/Block.cs index ab427c715..8c19e6bcf 100644 --- a/Minecraft.Server.FourKit/Block/Block.cs +++ b/Minecraft.Server.FourKit/Block/Block.cs @@ -89,7 +89,19 @@ public class Block /// Whether the change was successful. public bool setTypeId(int type) { - NativeBridge.SetTile?.Invoke(_world.getDimensionId(), _x, _y, _z, type, 0); + return setTypeId(type, true); + } + + /// + /// Sets the type ID of this block. + /// + /// Type ID to change this block to. + /// False to cancel physics on the changed block. + /// Whether the block was changed. + public bool setTypeId(int type, bool applyPhysics) + { + int flags = applyPhysics ? 3 : 2; + NativeBridge.SetTile?.Invoke(_world.getDimensionId(), _x, _y, _z, type, 0, flags); return true; } @@ -108,7 +120,43 @@ public class Block /// New block specific metadata. public void setData(byte data) { - NativeBridge.SetTileData?.Invoke(_world.getDimensionId(), _x, _y, _z, data); + setData(data, true); + } + + /// + /// Sets the metadata for this block. + /// + /// New block specific metadata. + /// False to cancel physics from the changed block. + public void setData(byte data, bool applyPhysics) + { + int flags = applyPhysics ? 3 : 2; + NativeBridge.SetTileData?.Invoke(_world.getDimensionId(), _x, _y, _z, data, flags); + } + + /// + /// Sets the type ID and data of this block. + /// + /// Type ID to change this block to. + /// The data value to change this block to. + /// Whether the block was changed. + public bool setTypeIdAndData(int type, byte data) + { + return setTypeIdAndData(type, data, true); + } + + /// + /// Sets the type ID and data of this block. + /// + /// Type ID to change this block to. + /// The data value to change this block to. + /// False to cancel physics on the changed block. + /// Whether the block was changed. + public bool setTypeIdAndData(int type, byte data, bool applyPhysics) + { + int flags = applyPhysics ? 3 : 2; + NativeBridge.SetTile?.Invoke(_world.getDimensionId(), _x, _y, _z, type, data, flags); + return true; } /// diff --git a/Minecraft.Server.FourKit/Block/BlockState.cs b/Minecraft.Server.FourKit/Block/BlockState.cs index 8420064c4..33d3493aa 100644 --- a/Minecraft.Server.FourKit/Block/BlockState.cs +++ b/Minecraft.Server.FourKit/Block/BlockState.cs @@ -200,7 +200,7 @@ public class BlockState if (!force && currentType != _typeId) return false; - NativeBridge.SetTile(_world.getDimensionId(), _x, _y, _z, _typeId, _data); + NativeBridge.SetTile(_world.getDimensionId(), _x, _y, _z, _typeId, _data, applyPhysics ? 3 : 2); return true; } diff --git a/Minecraft.Server.FourKit/ChatColor.cs b/Minecraft.Server.FourKit/ChatColor.cs new file mode 100644 index 000000000..cbfb066a0 --- /dev/null +++ b/Minecraft.Server.FourKit/ChatColor.cs @@ -0,0 +1,173 @@ +using System.Text; +using System.Text.RegularExpressions; + +namespace Minecraft.Server.FourKit; + +/// +/// All supported color values for chat. +/// +public class ChatColor +{ + /// + /// The special character which prefixes all chat colour codes. + /// + public static readonly char COLOR_CHAR = '\u00A7'; // F + + private static readonly Regex STRIP_COLOR_PATTERN = + new Regex("(?i)" + COLOR_CHAR + "[0-9A-FK-OR]", RegexOptions.Compiled); + + private static readonly Dictionary BY_CHAR = new(); + + /// Represents black. + public static readonly ChatColor BLACK = new('0', false); + /// Represents dark blue. + public static readonly ChatColor DARK_BLUE = new('1', false); + /// Represents dark green. + public static readonly ChatColor DARK_GREEN = new('2', false); + /// Represents dark blue (aqua). + public static readonly ChatColor DARK_AQUA = new('3', false); + /// Represents dark red. + public static readonly ChatColor DARK_RED = new('4', false); + /// Represents dark purple. + public static readonly ChatColor DARK_PURPLE = new('5', false); + /// Represents gold. + public static readonly ChatColor GOLD = new('6', false); + /// Represents gray. + public static readonly ChatColor GRAY = new('7', false); + /// Represents dark gray. + public static readonly ChatColor DARK_GRAY = new('8', false); + /// Represents blue. + public static readonly ChatColor BLUE = new('9', false); + /// Represents green. + public static readonly ChatColor GREEN = new('a', false); + /// Represents aqua. + public static readonly ChatColor AQUA = new('b', false); + /// Represents red. + public static readonly ChatColor RED = new('c', false); + /// Represents light purple. + public static readonly ChatColor LIGHT_PURPLE = new('d', false); + /// Represents yellow. + public static readonly ChatColor YELLOW = new('e', false); + /// Represents white. + public static readonly ChatColor WHITE = new('f', false); + /// Resets all previous chat colors or formats. + public static readonly ChatColor RESET = new('r', false); + + private readonly char _code; + private readonly bool _isFormat; + private readonly string _toString; + + private ChatColor(char code, bool isFormat) + { + _code = code; + _isFormat = isFormat; + _toString = new string(new[] { COLOR_CHAR, code }); + BY_CHAR[code] = this; + } + + /// + /// Gets the char value associated with this color. + /// + /// A char value of this color code. + public char getChar() => _code; + + /// + /// Checks if this code is a format code as opposed to a color code. + /// + /// true if this is a format code. + public bool isFormat() => _isFormat; + + /// + /// Checks if this code is a color code as opposed to a format code. + /// + /// true if this is a color code. + public bool isColor() => !_isFormat && this != RESET; + + /// + /// Gets the color represented by the specified color code. + /// + /// Code to check. + /// Associative ChatColor with the given code, or null if it doesn't exist. + public static ChatColor? getByChar(char code) + { + return BY_CHAR.TryGetValue(char.ToLower(code), out var color) ? color : null; + } + + /// + /// Gets the color represented by the specified color code. + /// + /// Code to check. + /// Associative ChatColor with the given code, or null if it doesn't exist. + public static ChatColor? getByChar(string code) + { + if (string.IsNullOrEmpty(code)) return null; + return getByChar(code[0]); + } + + /// + /// Strips the given message of all color codes. + /// + /// String to strip of color. + /// A copy of the input string, without any coloring. + public static string? stripColor(string? input) + { + if (input == null) return null; + return STRIP_COLOR_PATTERN.Replace(input, ""); + } + + /// + /// Translates a string using an alternate color code character into a string + /// that uses the internal color code character. + /// The alternate color code character will only be replaced if it is immediately + /// followed by 0-9, A-F, a-f, K-O, k-o, R or r. + /// + /// The alternate color code character to replace. Ex: & + /// Text containing the alternate color code character. + /// Text containing the color code character. + public static string translateAlternateColorCodes(char altColorChar, string textToTranslate) + { + char[] b = textToTranslate.ToCharArray(); + for (int i = 0; i < b.Length - 1; i++) + { + if (b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".IndexOf(b[i + 1]) > -1) + { + b[i] = COLOR_CHAR; + } + } + return new string(b); + } + + /// + /// Gets the ChatColors used at the end of the given input string. + /// + /// Input string to retrieve the colors from. + /// Any remaining ChatColors to pass onto the next line. + public static string getLastColors(string input) + { + var result = new StringBuilder(); + int length = input.Length; + + for (int index = length - 1; index > -1; index--) + { + char section = input[index]; + if (section == COLOR_CHAR && index < length - 1) + { + char c = input[index + 1]; + ChatColor? color = getByChar(c); + if (color != null) + { + result.Insert(0, color.ToString()); + if (color.isColor() || color == RESET) + break; + } + } + } + + return result.ToString(); + } + + public static string operator +(ChatColor color, string text) => color.ToString() + text; + + /// + public override string ToString() => _toString; +} diff --git a/Minecraft.Server.FourKit/NativeBridge.cs b/Minecraft.Server.FourKit/NativeBridge.cs index 753cf898b..b936e390e 100644 --- a/Minecraft.Server.FourKit/NativeBridge.cs +++ b/Minecraft.Server.FourKit/NativeBridge.cs @@ -43,10 +43,10 @@ internal static class NativeBridge internal delegate int NativeGetTileDataDelegate(int dimId, int x, int y, int z); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate void NativeSetTileDelegate(int dimId, int x, int y, int z, int tileId, int data); + internal delegate void NativeSetTileDelegate(int dimId, int x, int y, int z, int tileId, int data, int flags); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - internal delegate void NativeSetTileDataDelegate(int dimId, int x, int y, int z, int data); + internal delegate void NativeSetTileDataDelegate(int dimId, int x, int y, int z, int data, int flags); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate int NativeBreakBlockDelegate(int dimId, int x, int y, int z); diff --git a/Minecraft.Server/FourKitNatives.cpp b/Minecraft.Server/FourKitNatives.cpp index a79d53f36..f60658268 100644 --- a/Minecraft.Server/FourKitNatives.cpp +++ b/Minecraft.Server/FourKitNatives.cpp @@ -309,20 +309,20 @@ int __cdecl NativeGetTileData(int dimId, int x, int y, int z) return level->getData(x, y, z); } -void __cdecl NativeSetTile(int dimId, int x, int y, int z, int tileId, int data) +void __cdecl NativeSetTile(int dimId, int x, int y, int z, int tileId, int data, int flags) { ServerLevel *level = GetLevel(dimId); if (!level) return; - level->setTileAndData(x, y, z, tileId, data, Tile::UPDATE_ALL); + level->setTileAndData(x, y, z, tileId, data, flags); } -void __cdecl NativeSetTileData(int dimId, int x, int y, int z, int data) +void __cdecl NativeSetTileData(int dimId, int x, int y, int z, int data, int flags) { ServerLevel *level = GetLevel(dimId); if (!level) return; - level->setData(x, y, z, data, Tile::UPDATE_ALL); + level->setData(x, y, z, data, flags); } int __cdecl NativeBreakBlock(int dimId, int x, int y, int z) diff --git a/Minecraft.Server/FourKitNatives.h b/Minecraft.Server/FourKitNatives.h index fb1050343..ae241e862 100644 --- a/Minecraft.Server/FourKitNatives.h +++ b/Minecraft.Server/FourKitNatives.h @@ -18,8 +18,8 @@ namespace FourKitBridge // World int __cdecl NativeGetTileId(int dimId, int x, int y, int z); int __cdecl NativeGetTileData(int dimId, int x, int y, int z); - void __cdecl NativeSetTile(int dimId, int x, int y, int z, int tileId, int data); - void __cdecl NativeSetTileData(int dimId, int x, int y, int z, int data); + void __cdecl NativeSetTile(int dimId, int x, int y, int z, int tileId, int data, int flags); + void __cdecl NativeSetTileData(int dimId, int x, int y, int z, int data, int flags); int __cdecl NativeBreakBlock(int dimId, int x, int y, int z); int __cdecl NativeGetHighestBlockY(int dimId, int x, int z); void __cdecl NativeGetWorldInfo(int dimId, double *outBuf);