mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-04-26 08:57:24 +00:00
cleanup
This commit is contained in:
parent
98be92ed0c
commit
def50adfcc
|
|
@ -263,7 +263,7 @@ bool ServerPlayerGameMode::destroyBlock(int x, int y, int z)
|
|||
{
|
||||
if (!EnchantmentHelper::hasSilkTouch(player))
|
||||
{
|
||||
// todo: shouldnt we get these values from the actual blocks?
|
||||
// (SYLV)todo: shouldnt we get these values from the actual blocks?
|
||||
if (t == Tile::coalOre_Id)
|
||||
eventExp = Mth::nextInt(level->random, 0, 2);
|
||||
else if (t == Tile::diamondOre_Id)
|
||||
|
|
@ -286,7 +286,6 @@ bool ServerPlayerGameMode::destroyBlock(int x, int y, int z)
|
|||
int breakResult = FourKitBridge::FireBlockBreak(player->entityId, dimId, x, y, z, t, data, eventExp);
|
||||
if (breakResult < 0)
|
||||
{
|
||||
// Cancelled: send block correction to client
|
||||
player->connection->send(std::make_shared<TileUpdatePacket>(x, y, z, level));
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
111
Minecraft.Server.FourKit/FourKitHost.Callbacks.cs
Normal file
111
Minecraft.Server.FourKit/FourKitHost.Callbacks.cs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Minecraft.Server.FourKit;
|
||||
|
||||
public static partial class FourKitHost
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetNativeCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetCallbacks(damage, setHealth, teleport, setGameMode, broadcastMessage, setFallDistance, getPlayerSnapshot, sendMessage, setWalkSpeed, teleportEntity);
|
||||
ServerLog.Info("fourkit", "Native callbacks registered.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetNativeCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetWorldCallbacks(IntPtr getTileId, IntPtr getTileData, IntPtr setTile, IntPtr setTileData, IntPtr breakBlock, IntPtr getHighestBlockY, IntPtr getWorldInfo, IntPtr setWorldTime, IntPtr setWeather, IntPtr createExplosion, IntPtr strikeLightning, IntPtr setSpawnLocation, IntPtr dropItem)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetWorldCallbacks(getTileId, getTileData, setTile, setTileData, breakBlock, getHighestBlockY, getWorldInfo, setWorldTime, setWeather, createExplosion, strikeLightning, setSpawnLocation, dropItem);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetWorldCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetPlayerCallbacks(IntPtr kickPlayer, IntPtr banPlayer, IntPtr banPlayerIp, IntPtr getPlayerAddress)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetPlayerCallbacks(kickPlayer, banPlayer, banPlayerIp, getPlayerAddress);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetPlayerCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetInventoryCallbacks(IntPtr getPlayerInventory, IntPtr setPlayerInventorySlot, IntPtr getContainerContents, IntPtr setContainerSlot, IntPtr getContainerViewerEntityIds, IntPtr closeContainer, IntPtr openVirtualContainer, IntPtr getItemMeta, IntPtr setItemMeta, IntPtr setHeldItemSlot)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetInventoryCallbacks(getPlayerInventory, setPlayerInventorySlot, getContainerContents, setContainerSlot, getContainerViewerEntityIds, closeContainer, openVirtualContainer, getItemMeta, setItemMeta, setHeldItemSlot);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetInventoryCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetEntityCallbacks(IntPtr setSneaking, IntPtr setVelocity, IntPtr setAllowFlight, IntPtr playSound, IntPtr setSleepingIgnored)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetEntityCallbacks(setSneaking, setVelocity, setAllowFlight, playSound, setSleepingIgnored);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetEntityCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetExperienceCallbacks(IntPtr setLevel, IntPtr setExp, IntPtr giveExp, IntPtr giveExpLevels, IntPtr setFoodLevel, IntPtr setSaturation, IntPtr setExhaustion)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetExperienceCallbacks(setLevel, setExp, giveExp, giveExpLevels, setFoodLevel, setSaturation, setExhaustion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetExperienceCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetParticleCallbacks(IntPtr spawnParticle)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetParticleCallbacks(spawnParticle);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetParticleCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetVehicleCallbacks(IntPtr setPassenger, IntPtr leaveVehicle, IntPtr eject, IntPtr getVehicleId, IntPtr getPassengerId, IntPtr getEntityInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetVehicleCallbacks(setPassenger, leaveVehicle, eject, getVehicleId, getPassengerId, getEntityInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetVehicleCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
976
Minecraft.Server.FourKit/FourKitHost.Events.cs
Normal file
976
Minecraft.Server.FourKit/FourKitHost.Events.cs
Normal file
|
|
@ -0,0 +1,976 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using Minecraft.Server.FourKit.Block;
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Event;
|
||||
using Minecraft.Server.FourKit.Event.Block;
|
||||
using Minecraft.Server.FourKit.Event.Entity;
|
||||
using Minecraft.Server.FourKit.Event.Player;
|
||||
using Minecraft.Server.FourKit.Event.Inventory;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
|
||||
namespace Minecraft.Server.FourKit;
|
||||
|
||||
public static partial class FourKitHost
|
||||
{
|
||||
[UnmanagedCallersOnly]
|
||||
public static void FirePlayerJoin(int entityId, IntPtr namePtr, int nameByteLen, IntPtr uuidPtr, int uuidByteLen)
|
||||
{
|
||||
try
|
||||
{
|
||||
string name = nameByteLen > 0
|
||||
? Marshal.PtrToStringUTF8(namePtr, nameByteLen) ?? string.Empty
|
||||
: string.Empty;
|
||||
|
||||
string uuidStr = uuidByteLen > 0
|
||||
? Marshal.PtrToStringUTF8(uuidPtr, uuidByteLen) ?? string.Empty
|
||||
: string.Empty;
|
||||
|
||||
var player = FourKit.TrackPlayer(entityId, name);
|
||||
player.SetPlayerUniqueIdInternal(ParseOrHashGuid(uuidStr));
|
||||
SyncPlayerFromNative(player);
|
||||
var evt = new PlayerJoinEvent(player);
|
||||
FourKit.FireEvent(evt);
|
||||
BroadcastNativeMessage(evt.getJoinMessage());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerJoin error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void FirePlayerQuit(int entityId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.UntrackPlayer(entityId);
|
||||
if (player != null)
|
||||
{
|
||||
SyncPlayerFromNative(player);
|
||||
var evt = new PlayerQuitEvent(player);
|
||||
FourKit.FireEvent(evt);
|
||||
BroadcastNativeMessage(evt.getQuitMessage());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerQuit error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerKick(int entityId, int disconnectReason,
|
||||
IntPtr reasonPtr, int reasonByteLen,
|
||||
IntPtr outBuf, int outBufSize, IntPtr outLenPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var reason = Enum.IsDefined(typeof(DisconnectReason), disconnectReason)
|
||||
? (DisconnectReason)disconnectReason
|
||||
: DisconnectReason.NONE;
|
||||
|
||||
string defaultLeave = $"{player.getName()} was kicked from the game";
|
||||
var evt = new PlayerKickEvent(player, reason, defaultLeave);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
if (evt.isCancelled())
|
||||
{
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
string leaveMessage = evt.getLeaveMessage();
|
||||
if (!string.IsNullOrEmpty(leaveMessage))
|
||||
{
|
||||
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(leaveMessage);
|
||||
if (utf8Bytes.Length < outBufSize)
|
||||
{
|
||||
Marshal.Copy(utf8Bytes, 0, outBuf, utf8Bytes.Length);
|
||||
Marshal.WriteInt32(outLenPtr, utf8Bytes.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerKick error: {ex}");
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerMove(int entityId,
|
||||
double fromX, double fromY, double fromZ,
|
||||
double toX, double toY, double toZ,
|
||||
IntPtr outCoords)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.Copy(new double[] { toX, toY, toZ }, 0, outCoords, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var from = new Location(fromX, fromY, fromZ);
|
||||
var to = new Location(toX, toY, toZ);
|
||||
var evt = new PlayerMoveEvent(player, from, to);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
var finalTo = evt.getTo();
|
||||
Marshal.Copy(new double[] { finalTo.X, finalTo.Y, finalTo.Z }, 0, outCoords, 3);
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerMove error: {ex}");
|
||||
Marshal.Copy(new double[] { toX, toY, toZ }, 0, outCoords, 3);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void UpdatePlayerEntityId(int oldEntityId, int newEntityId)
|
||||
{
|
||||
try
|
||||
{
|
||||
FourKit.UpdatePlayerEntityId(oldEntityId, newEntityId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"UpdatePlayerEntityId error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerChat(int entityId, IntPtr msgPtr, int msgByteLen,
|
||||
IntPtr outBuf, int outBufSize, IntPtr outLenPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
string message = msgByteLen > 0
|
||||
? Marshal.PtrToStringUTF8(msgPtr, msgByteLen) ?? string.Empty
|
||||
: string.Empty;
|
||||
|
||||
var evt = new PlayerChatEvent(player, message);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
if (evt.isCancelled())
|
||||
{
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
string formatted = JavaFormat(evt.getFormat(), player.getDisplayName(), evt.getMessage());
|
||||
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(formatted);
|
||||
if (utf8Bytes.Length < outBufSize)
|
||||
{
|
||||
Marshal.Copy(utf8Bytes, 0, outBuf, utf8Bytes.Length);
|
||||
Marshal.WriteInt32(outLenPtr, utf8Bytes.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerChat error: {ex}");
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FireBlockPlace(int entityId, int dimId,
|
||||
int placedX, int placedY, int placedZ,
|
||||
int againstX, int againstY, int againstZ,
|
||||
int itemId, int itemCount, int canBuild)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
return 0;
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var world = FourKit.getWorld(dimId);
|
||||
var placedBlock = new Block.Block(world, placedX, placedY, placedZ);
|
||||
var againstBlock = new Block.Block(world, againstX, againstY, againstZ);
|
||||
|
||||
Material mat = Enum.IsDefined(typeof(Material), itemId) ? (Material)itemId : Material.AIR;
|
||||
var itemInHand = new ItemStack(mat, itemCount);
|
||||
|
||||
var evt = new BlockPlaceEvent(placedBlock, againstBlock, itemInHand, player, canBuild != 0);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireBlockPlace error: {ex}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FireBlockBreak(int entityId, int dimId,
|
||||
int x, int y, int z, int tileId, int data, int exp)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
return exp;
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var world = FourKit.getWorld(dimId);
|
||||
var block = new Block.Block(world, x, y, z);
|
||||
|
||||
var evt = new BlockBreakEvent(block, player, exp);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
if (evt.isCancelled())
|
||||
return -1;
|
||||
|
||||
return evt.getExpToDrop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireBlockBreak error: {ex}");
|
||||
return exp;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FireEntityDamage(int entityId, int entityTypeId, int dimId,
|
||||
double x, double y, double z, int causeId, double damage, IntPtr outDamage,
|
||||
int damagerEntityId, int damagerEntityTypeId,
|
||||
double damagerX, double damagerY, double damagerZ)
|
||||
{
|
||||
try
|
||||
{
|
||||
Entity.Entity? entity = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (entity is Player player)
|
||||
{
|
||||
SyncPlayerFromNative(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entityType = Enum.IsDefined(typeof(EntityType), entityTypeId)
|
||||
? (EntityType)entityTypeId
|
||||
: EntityType.UNKNOWN;
|
||||
entity = new LivingEntity(entityId, entityType, dimId, x, y, z);
|
||||
}
|
||||
|
||||
var cause = Enum.IsDefined(typeof(EntityDamageEvent.DamageCause), causeId)
|
||||
? (EntityDamageEvent.DamageCause)causeId
|
||||
: EntityDamageEvent.DamageCause.CUSTOM;
|
||||
|
||||
EntityDamageByEntityEvent? byEntityEvt = null;
|
||||
if (damagerEntityId >= 0)
|
||||
{
|
||||
Entity.Entity? damager = FourKit.GetPlayerByEntityId(damagerEntityId);
|
||||
if (damager is Player damagerPlayer)
|
||||
{
|
||||
SyncPlayerFromNative(damagerPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var damagerType = Enum.IsDefined(typeof(EntityType), damagerEntityTypeId)
|
||||
? (EntityType)damagerEntityTypeId
|
||||
: EntityType.UNKNOWN;
|
||||
damager = new LivingEntity(damagerEntityId, damagerType, dimId, damagerX, damagerY, damagerZ);
|
||||
}
|
||||
byEntityEvt = new EntityDamageByEntityEvent(damager, entity!, cause, damage);
|
||||
FourKit.FireEvent(byEntityEvt);
|
||||
damage = byEntityEvt.getDamage();
|
||||
}
|
||||
|
||||
var evt = new EntityDamageEvent(entity!, cause, damage);
|
||||
if (byEntityEvt != null && byEntityEvt.isCancelled())
|
||||
evt.setCancelled(true);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
Marshal.Copy(new double[] { evt.getDamage() }, 0, outDamage, 1);
|
||||
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireEntityDamage error: {ex}");
|
||||
Marshal.Copy(new double[] { damage }, 0, outDamage, 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FireSignChange(int entityId, int dimId,
|
||||
int x, int y, int z,
|
||||
IntPtr line0Ptr, int line0Len,
|
||||
IntPtr line1Ptr, int line1Len,
|
||||
IntPtr line2Ptr, int line2Len,
|
||||
IntPtr line3Ptr, int line3Len,
|
||||
IntPtr outBuf, int outBufSize, IntPtr outLensPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
WriteSignOutLens(outLensPtr, [0, 0, 0, 0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
string[] lines =
|
||||
[
|
||||
line0Len > 0 ? Marshal.PtrToStringUTF8(line0Ptr, line0Len) ?? string.Empty : string.Empty,
|
||||
line1Len > 0 ? Marshal.PtrToStringUTF8(line1Ptr, line1Len) ?? string.Empty : string.Empty,
|
||||
line2Len > 0 ? Marshal.PtrToStringUTF8(line2Ptr, line2Len) ?? string.Empty : string.Empty,
|
||||
line3Len > 0 ? Marshal.PtrToStringUTF8(line3Ptr, line3Len) ?? string.Empty : string.Empty,
|
||||
];
|
||||
|
||||
var world = FourKit.getWorld(dimId);
|
||||
var block = new Block.Block(world, x, y, z);
|
||||
var evt = new Event.Block.SignChangeEvent(block, player, lines);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
int offset = 0;
|
||||
int[] lens = new int[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes(evt.getLine(i));
|
||||
if (offset + utf8.Length <= outBufSize)
|
||||
{
|
||||
Marshal.Copy(utf8, 0, outBuf + offset, utf8.Length);
|
||||
lens[i] = utf8.Length;
|
||||
offset += utf8.Length;
|
||||
}
|
||||
}
|
||||
WriteSignOutLens(outLensPtr, lens);
|
||||
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireSignChange error: {ex}");
|
||||
WriteSignOutLens(outLensPtr, [0, 0, 0, 0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FireEntityDeath(int entityId, int entityTypeId, int dimId,
|
||||
double x, double y, double z, int exp)
|
||||
{
|
||||
try
|
||||
{
|
||||
var entityType = Enum.IsDefined(typeof(EntityType), entityTypeId)
|
||||
? (EntityType)entityTypeId
|
||||
: EntityType.UNKNOWN;
|
||||
var entity = new LivingEntity(entityId, entityType, dimId, x, y, z);
|
||||
|
||||
var drops = new List<ItemStack>();
|
||||
var evt = new EntityDeathEvent(entity, drops, exp);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
return evt.getDroppedExp();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireEntityDeath error: {ex}");
|
||||
return exp;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerDeath(int entityId,
|
||||
IntPtr deathMsgPtr, int deathMsgByteLen, int exp,
|
||||
IntPtr outMsgBuf, int outMsgBufSize, IntPtr outMsgLenPtr, IntPtr outKeepInventoryPtr,
|
||||
IntPtr outNewExpPtr, IntPtr outNewLevelPtr, IntPtr outKeepLevelPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.WriteInt32(outMsgLenPtr, 0);
|
||||
Marshal.WriteInt32(outKeepInventoryPtr, 0);
|
||||
Marshal.WriteInt32(outNewExpPtr, 0);
|
||||
Marshal.WriteInt32(outNewLevelPtr, 0);
|
||||
Marshal.WriteInt32(outKeepLevelPtr, 0);
|
||||
return exp;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
string deathMessage = deathMsgByteLen > 0
|
||||
? Marshal.PtrToStringUTF8(deathMsgPtr, deathMsgByteLen) ?? string.Empty
|
||||
: string.Empty;
|
||||
|
||||
var drops = new List<ItemStack>();
|
||||
|
||||
var playerEvt = new PlayerDeathEvent(player, drops, exp, deathMessage);
|
||||
FourKit.FireEvent(playerEvt);
|
||||
|
||||
var entityEvt = new EntityDeathEvent(player, playerEvt.getDrops(), playerEvt.getDroppedExp());
|
||||
FourKit.FireEvent(entityEvt);
|
||||
|
||||
int finalExp = entityEvt.getDroppedExp();
|
||||
|
||||
string finalMsg = playerEvt.getDeathMessage();
|
||||
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(finalMsg);
|
||||
if (utf8Bytes.Length < outMsgBufSize)
|
||||
{
|
||||
Marshal.Copy(utf8Bytes, 0, outMsgBuf, utf8Bytes.Length);
|
||||
Marshal.WriteInt32(outMsgLenPtr, utf8Bytes.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Marshal.WriteInt32(outMsgLenPtr, 0);
|
||||
}
|
||||
|
||||
Marshal.WriteInt32(outKeepInventoryPtr, playerEvt.getKeepInventory() ? 1 : 0);
|
||||
Marshal.WriteInt32(outNewExpPtr, playerEvt.getNewExp());
|
||||
Marshal.WriteInt32(outNewLevelPtr, playerEvt.getNewLevel());
|
||||
Marshal.WriteInt32(outKeepLevelPtr, playerEvt.getKeepLevel() ? 1 : 0);
|
||||
|
||||
return finalExp;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerDeath error: {ex}");
|
||||
Marshal.WriteInt32(outMsgLenPtr, 0);
|
||||
Marshal.WriteInt32(outKeepInventoryPtr, 0);
|
||||
Marshal.WriteInt32(outNewExpPtr, 0);
|
||||
Marshal.WriteInt32(outNewLevelPtr, 0);
|
||||
Marshal.WriteInt32(outKeepLevelPtr, 0);
|
||||
return exp;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static long FirePlayerDropItem(int entityId, int itemId, int itemCount, int itemAux,
|
||||
IntPtr outItemIdPtr, IntPtr outItemCountPtr, IntPtr outItemAuxPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.WriteInt32(outItemIdPtr, itemId);
|
||||
Marshal.WriteInt32(outItemCountPtr, itemCount);
|
||||
Marshal.WriteInt32(outItemAuxPtr, itemAux);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
Material mat = Enum.IsDefined(typeof(Material), itemId) ? (Material)itemId : Material.AIR;
|
||||
var itemStack = new ItemStack(mat, itemCount, (short)itemAux);
|
||||
|
||||
var evt = new PlayerDropItemEvent(player, itemStack);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
var result = evt.getItemDrop();
|
||||
Marshal.WriteInt32(outItemIdPtr, result.getTypeId());
|
||||
Marshal.WriteInt32(outItemCountPtr, result.getAmount());
|
||||
Marshal.WriteInt32(outItemAuxPtr, result.getDurability());
|
||||
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerDropItem error: {ex}");
|
||||
Marshal.WriteInt32(outItemIdPtr, itemId);
|
||||
Marshal.WriteInt32(outItemCountPtr, itemCount);
|
||||
Marshal.WriteInt32(outItemAuxPtr, itemAux);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerInteract(int entityId, int action,
|
||||
int itemId, int itemCount, int itemAux,
|
||||
int clickedX, int clickedY, int clickedZ,
|
||||
int blockFace, int dimId,
|
||||
IntPtr outUseItemInHandPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.WriteInt32(outUseItemInHandPtr, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var actionEnum = Enum.IsDefined(typeof(Block.Action), action)
|
||||
? (Block.Action)action
|
||||
: Block.Action.RIGHT_CLICK_AIR;
|
||||
|
||||
var faceEnum = Enum.IsDefined(typeof(Block.BlockFace), blockFace)
|
||||
? (Block.BlockFace)blockFace
|
||||
: Block.BlockFace.SELF;
|
||||
|
||||
ItemStack? itemStack = null;
|
||||
if (itemId > 0)
|
||||
itemStack = new ItemStack(itemId, itemCount, (short)itemAux);
|
||||
|
||||
Block.Block? clickedBlock = null;
|
||||
bool hasBlock = actionEnum == Block.Action.LEFT_CLICK_BLOCK
|
||||
|| actionEnum == Block.Action.RIGHT_CLICK_BLOCK
|
||||
|| actionEnum == Block.Action.PHYSICAL;
|
||||
if (hasBlock)
|
||||
{
|
||||
var world = FourKit.getWorld(dimId);
|
||||
if (world != null)
|
||||
clickedBlock = new Block.Block(world, clickedX, clickedY, clickedZ);
|
||||
}
|
||||
|
||||
var evt = new PlayerInteractEvent(
|
||||
player, actionEnum, itemStack, clickedBlock, faceEnum);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
Marshal.WriteInt32(outUseItemInHandPtr, evt.useItemInHand() ? 1 : 0);
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerInteract error: {ex}");
|
||||
Marshal.WriteInt32(outUseItemInHandPtr, 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerInteractEntity(int playerEntityId,
|
||||
int targetEntityId, int targetEntityTypeId,
|
||||
int dimId, double targetX, double targetY, double targetZ,
|
||||
float targetHealth, float targetMaxHealth, float targetEyeHeight)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(playerEntityId);
|
||||
if (player == null)
|
||||
return 0;
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
Entity.Entity? target = FourKit.GetPlayerByEntityId(targetEntityId);
|
||||
if (target is Player targetPlayer)
|
||||
{
|
||||
SyncPlayerFromNative(targetPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entityType = Enum.IsDefined(typeof(EntityType), targetEntityTypeId)
|
||||
? (EntityType)targetEntityTypeId
|
||||
: EntityType.UNKNOWN;
|
||||
var living = new LivingEntity(targetEntityId, entityType, dimId, targetX, targetY, targetZ,
|
||||
targetHealth, targetMaxHealth);
|
||||
living.SetEyeHeightInternal(targetEyeHeight);
|
||||
target = living;
|
||||
}
|
||||
|
||||
var evt = new PlayerInteractEntityEvent(player, target);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerInteractEntity error: {ex}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerPickupItem(int playerEntityId,
|
||||
int itemEntityId, int dimId, double itemX, double itemY, double itemZ,
|
||||
int itemId, int itemCount, int itemAux, int remaining,
|
||||
IntPtr outItemIdPtr, IntPtr outItemCountPtr, IntPtr outItemAuxPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(playerEntityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.WriteInt32(outItemIdPtr, itemId);
|
||||
Marshal.WriteInt32(outItemCountPtr, itemCount);
|
||||
Marshal.WriteInt32(outItemAuxPtr, itemAux);
|
||||
// todo: fix
|
||||
return 1;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var itemStack = new Inventory.ItemStack(itemId, itemCount, (short)itemAux);
|
||||
var item = new Entity.Item(itemEntityId, dimId, itemX, itemY, itemZ, itemStack);
|
||||
var evt = new PlayerPickupItemEvent(player, item, remaining);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
var result = evt.getItem().getItemStack();
|
||||
Marshal.WriteInt32(outItemIdPtr, result.getTypeId());
|
||||
Marshal.WriteInt32(outItemCountPtr, result.getAmount());
|
||||
Marshal.WriteInt32(outItemAuxPtr, result.getDurability());
|
||||
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerPickupItem error: {ex}");
|
||||
Marshal.WriteInt32(outItemIdPtr, itemId);
|
||||
Marshal.WriteInt32(outItemCountPtr, itemCount);
|
||||
Marshal.WriteInt32(outItemAuxPtr, itemAux);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FireInventoryOpen(int entityId, int nativeContainerType,
|
||||
IntPtr titlePtr, int titleByteLen, int containerSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null) return 0;
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
string title = titleByteLen > 0
|
||||
? Marshal.PtrToStringUTF8(titlePtr, titleByteLen) ?? string.Empty
|
||||
: string.Empty;
|
||||
|
||||
InventoryType invType = MapNativeContainerType(nativeContainerType);
|
||||
Inventory.Inventory topInv = CreateContainerInventory(invType, nativeContainerType, title, containerSize, entityId);
|
||||
var bottomInv = player.getInventory();
|
||||
|
||||
var view = new InventoryView(topInv, bottomInv, player, invType);
|
||||
var evt = new InventoryOpenEvent(view);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireInventoryOpen error: {ex}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FireInventoryClick(int entityId, int slot, int button, int clickType,
|
||||
int nativeContainerType, int containerSize, IntPtr titleUtf8Ptr, int titleByteLen)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null) return 0;
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
ClickType click = MapNativeClickType(clickType, button);
|
||||
InventoryAction action = DetermineInventoryAction(click, slot);
|
||||
|
||||
InventoryType invType;
|
||||
Inventory.Inventory topInv;
|
||||
if (nativeContainerType < 0)
|
||||
{
|
||||
invType = InventoryType.PLAYER;
|
||||
topInv = player.getInventory();
|
||||
}
|
||||
else
|
||||
{
|
||||
invType = MapNativeContainerType(nativeContainerType);
|
||||
int size = containerSize > 0 ? containerSize : invType.getDefaultSize();
|
||||
string title = titleByteLen > 0 && titleUtf8Ptr != IntPtr.Zero
|
||||
? Marshal.PtrToStringUTF8(titleUtf8Ptr, titleByteLen) ?? invType.getDefaultTitle()
|
||||
: invType.getDefaultTitle();
|
||||
topInv = CreateContainerInventory(invType, nativeContainerType, title, size, entityId);
|
||||
}
|
||||
|
||||
var bottomInv = player.getInventory();
|
||||
var view = new InventoryView(topInv, bottomInv, player, invType);
|
||||
|
||||
SlotType slotType = SlotType.CONTAINER;
|
||||
if (slot == InventoryView.OUTSIDE)
|
||||
slotType = SlotType.OUTSIDE;
|
||||
|
||||
Inventory.Inventory._slotModifiedByPlugin = false;
|
||||
int hotbarKey = click == ClickType.NUMBER_KEY ? button : -1;
|
||||
var evt = new InventoryClickEvent(view, slotType, slot, click, action, hotbarKey);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
if (evt.isCancelled()) return 1;
|
||||
if (Inventory.Inventory._slotModifiedByPlugin) return 2;
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireInventoryClick error: {ex}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int HandlePlayerCommand(int entityId, IntPtr cmdUtf8, int cmdByteLen)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
return 0;
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
string commandLine = cmdByteLen > 0
|
||||
? Marshal.PtrToStringUTF8(cmdUtf8, cmdByteLen) ?? string.Empty
|
||||
: string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(commandLine))
|
||||
return 0;
|
||||
|
||||
return FourKit.DispatchCommand(player, commandLine) ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"HandlePlayerCommand error: {ex}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int HandleConsoleCommand(IntPtr cmdUtf8, int cmdByteLen)
|
||||
{
|
||||
try
|
||||
{
|
||||
string commandLine = cmdByteLen > 0
|
||||
? Marshal.PtrToStringUTF8(cmdUtf8, cmdByteLen) ?? string.Empty
|
||||
: string.Empty;
|
||||
|
||||
if (string.IsNullOrEmpty(commandLine))
|
||||
return 0;
|
||||
|
||||
string trimmed = commandLine.StartsWith('/') ? commandLine[1..] : commandLine;
|
||||
string[] parts = trimmed.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length == 0)
|
||||
return 0;
|
||||
|
||||
if (!FourKit.HasCommand(parts[0]))
|
||||
return 0;
|
||||
|
||||
FourKit.DispatchCommand(FourKit.getConsoleSender(), commandLine);
|
||||
return 1;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"HandleConsoleCommand error: {ex}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int GetPluginCommandHelp(IntPtr outBuf, int outBufSize, IntPtr outLenPtr)
|
||||
{
|
||||
try
|
||||
{
|
||||
var entries = FourKit.GetRegisteredCommandHelp();
|
||||
if (entries.Count == 0)
|
||||
{
|
||||
if (outLenPtr != IntPtr.Zero)
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var sb = new System.Text.StringBuilder();
|
||||
foreach (var (usage, description) in entries)
|
||||
{
|
||||
sb.Append(usage);
|
||||
sb.Append('\0');
|
||||
sb.Append(description);
|
||||
sb.Append('\0');
|
||||
}
|
||||
|
||||
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes(sb.ToString());
|
||||
int copyLen = Math.Min(utf8.Length, outBufSize);
|
||||
if (outBuf != IntPtr.Zero && copyLen > 0)
|
||||
Marshal.Copy(utf8, 0, outBuf, copyLen);
|
||||
if (outLenPtr != IntPtr.Zero)
|
||||
Marshal.WriteInt32(outLenPtr, copyLen);
|
||||
|
||||
return entries.Count;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"GetPluginCommandHelp error: {ex}");
|
||||
if (outLenPtr != IntPtr.Zero)
|
||||
Marshal.WriteInt32(outLenPtr, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerTeleport(int entityId,
|
||||
double fromX, double fromY, double fromZ, int fromDimId,
|
||||
double toX, double toY, double toZ, int toDimId,
|
||||
int cause, IntPtr outCoords)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.Copy(new double[] { toX, toY, toZ }, 0, outCoords, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var fromWorld = FourKit.getWorld(fromDimId);
|
||||
var toWorld = FourKit.getWorld(toDimId);
|
||||
var from = new Location(fromWorld, fromX, fromY, fromZ);
|
||||
var to = new Location(toWorld, toX, toY, toZ);
|
||||
var teleportCause = cause >= 0 && cause <= (int)PlayerTeleportEvent.TeleportCause.UNKNOWN
|
||||
? (PlayerTeleportEvent.TeleportCause)cause
|
||||
: PlayerTeleportEvent.TeleportCause.UNKNOWN;
|
||||
|
||||
var evt = new PlayerTeleportEvent(player, from, to, teleportCause);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
var finalTo = evt.getTo();
|
||||
Marshal.Copy(new double[] { finalTo.X, finalTo.Y, finalTo.Z }, 0, outCoords, 3);
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerTeleport error: {ex}");
|
||||
Marshal.Copy(new double[] { toX, toY, toZ }, 0, outCoords, 3);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerPortal(int entityId,
|
||||
double fromX, double fromY, double fromZ, int fromDimId,
|
||||
double toX, double toY, double toZ, int toDimId,
|
||||
int cause, IntPtr outCoords)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null)
|
||||
{
|
||||
Marshal.Copy(new double[] { toX, toY, toZ }, 0, outCoords, 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var fromWorld = FourKit.getWorld(fromDimId);
|
||||
var toWorld = FourKit.getWorld(toDimId);
|
||||
var from = new Location(fromWorld, fromX, fromY, fromZ);
|
||||
var to = new Location(toWorld, toX, toY, toZ);
|
||||
var teleportCause = cause >= 0 && cause <= (int)PlayerTeleportEvent.TeleportCause.UNKNOWN
|
||||
? (PlayerTeleportEvent.TeleportCause)cause
|
||||
: PlayerTeleportEvent.TeleportCause.UNKNOWN;
|
||||
|
||||
var evt = new PlayerPortalEvent(player, from, to, teleportCause);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
var finalTo = evt.getTo();
|
||||
Marshal.Copy(new double[] { finalTo.X, finalTo.Y, finalTo.Z }, 0, outCoords, 3);
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FirePlayerPortal error: {ex}");
|
||||
Marshal.Copy(new double[] { toX, toY, toZ }, 0, outCoords, 3);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FireBedEnter(int entityId, int dimId, int bedX, int bedY, int bedZ)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null) return 0;
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var world = FourKit.getWorld(dimId);
|
||||
var bed = new Block.Block(world, bedX, bedY, bedZ);
|
||||
var evt = new Event.Player.PlayerBedEnterEvent(player, bed);
|
||||
FourKit.FireEvent(evt);
|
||||
|
||||
return evt.isCancelled() ? 1 : 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireBedEnter error: {ex}");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void FireBedLeave(int entityId, int dimId, int bedX, int bedY, int bedZ)
|
||||
{
|
||||
try
|
||||
{
|
||||
var player = FourKit.GetPlayerByEntityId(entityId);
|
||||
if (player == null) return;
|
||||
|
||||
SyncPlayerFromNative(player);
|
||||
|
||||
var world = FourKit.getWorld(dimId);
|
||||
var bed = new Block.Block(world, bedX, bedY, bedZ);
|
||||
var evt = new Event.Player.PlayerBedLeaveEvent(player, bed);
|
||||
FourKit.FireEvent(evt);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireBedLeave error: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
251
Minecraft.Server/FourKitMappers.cpp
Normal file
251
Minecraft.Server/FourKitMappers.cpp
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
#include "FourKitBridge.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "..\Minecraft.World\DamageSource.h"
|
||||
#include "..\Minecraft.World\EntityDamageSource.h"
|
||||
|
||||
namespace FourKitBridge
|
||||
{
|
||||
int MapEntityType(int nativeType)
|
||||
{
|
||||
eINSTANCEOF type = (eINSTANCEOF)nativeType;
|
||||
const int ARROW = 0, BAT = 1, BLAZE = 2, BOAT = 3, CAVE_SPIDER = 4;
|
||||
const int CHICKEN = 5, COW = 7, CREEPER = 8, DROPPED_ITEM = 9;
|
||||
const int EGG = 10, ENDER_CRYSTAL = 11, ENDER_DRAGON = 12;
|
||||
const int ENDER_PEARL = 13, ENDER_SIGNAL = 14, ENDERMAN = 15;
|
||||
const int EXPERIENCE_ORB = 16, FALLING_BLOCK = 17, FIREBALL = 18;
|
||||
const int FIREWORK = 19, FISHING_HOOK = 20, GHAST = 21, GIANT = 22;
|
||||
const int HORSE = 23, IRON_GOLEM = 24, ITEM_FRAME = 25;
|
||||
const int LEASH_HITCH = 26, LIGHTNING = 27, MAGMA_CUBE = 28;
|
||||
const int MINECART = 29, MINECART_CHEST = 30, MINECART_FURNACE = 32;
|
||||
const int MINECART_HOPPER = 33, MINECART_MOB_SPAWNER = 34;
|
||||
const int MINECART_TNT = 35, MUSHROOM_COW = 36, OCELOT = 37;
|
||||
const int PAINTING = 38, PIG = 39, PIG_ZOMBIE = 40, PLAYER = 41;
|
||||
const int PRIMED_TNT = 42, SHEEP = 43, SILVERFISH = 44;
|
||||
const int SKELETON = 45, SLIME = 46, SMALL_FIREBALL = 47;
|
||||
const int SNOWBALL = 48, SNOWMAN = 49, SPIDER = 50;
|
||||
const int SPLASH_POTION = 51, SQUID = 52, THROWN_EXP_BOTTLE = 53;
|
||||
const int UNKNOWN = 54, VILLAGER = 55, WITCH = 57;
|
||||
const int WITHER = 58, WITHER_SKULL = 59, WOLF = 60, ZOMBIE = 61;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case eTYPE_ARROW:
|
||||
return ARROW;
|
||||
case eTYPE_BAT:
|
||||
return BAT;
|
||||
case eTYPE_BLAZE:
|
||||
return BLAZE;
|
||||
case eTYPE_BOAT:
|
||||
return BOAT;
|
||||
case eTYPE_CAVESPIDER:
|
||||
return CAVE_SPIDER;
|
||||
case eTYPE_CHICKEN:
|
||||
return CHICKEN;
|
||||
case eTYPE_COW:
|
||||
return COW;
|
||||
case eTYPE_CREEPER:
|
||||
return CREEPER;
|
||||
case eTYPE_ITEMENTITY:
|
||||
return DROPPED_ITEM;
|
||||
case eTYPE_THROWNEGG:
|
||||
return EGG;
|
||||
case eTYPE_NETHER_SPHERE:
|
||||
return ENDER_CRYSTAL;
|
||||
case eTYPE_ENDERDRAGON:
|
||||
return ENDER_DRAGON;
|
||||
case eTYPE_THROWNENDERPEARL:
|
||||
return ENDER_PEARL;
|
||||
case eTYPE_EYEOFENDERSIGNAL:
|
||||
return ENDER_SIGNAL;
|
||||
case eTYPE_ENDERMAN:
|
||||
return ENDERMAN;
|
||||
case eTYPE_EXPERIENCEORB:
|
||||
return EXPERIENCE_ORB;
|
||||
case eTYPE_FALLINGTILE:
|
||||
return FALLING_BLOCK;
|
||||
case eTYPE_LARGE_FIREBALL:
|
||||
return FIREBALL;
|
||||
case eTYPE_FIREWORKS_ROCKET:
|
||||
return FIREWORK;
|
||||
case eTYPE_FISHINGHOOK:
|
||||
return FISHING_HOOK;
|
||||
case eTYPE_GHAST:
|
||||
return GHAST;
|
||||
case eTYPE_GIANT:
|
||||
return GIANT;
|
||||
case eTYPE_HORSE:
|
||||
return HORSE;
|
||||
case eTYPE_VILLAGERGOLEM:
|
||||
return IRON_GOLEM;
|
||||
case eTYPE_ITEM_FRAME:
|
||||
return ITEM_FRAME;
|
||||
case eTYPE_LEASHFENCEKNOT:
|
||||
return LEASH_HITCH;
|
||||
case eTYPE_LIGHTNINGBOLT:
|
||||
return LIGHTNING;
|
||||
case eTYPE_LAVASLIME:
|
||||
return MAGMA_CUBE;
|
||||
case eTYPE_MINECART_RIDEABLE:
|
||||
return MINECART;
|
||||
case eTYPE_MINECART_CHEST:
|
||||
return MINECART_CHEST;
|
||||
case eTYPE_MINECART_FURNACE:
|
||||
return MINECART_FURNACE;
|
||||
case eTYPE_MINECART_HOPPER:
|
||||
return MINECART_HOPPER;
|
||||
case eTYPE_MINECART_SPAWNER:
|
||||
return MINECART_MOB_SPAWNER;
|
||||
case eTYPE_MINECART_TNT:
|
||||
return MINECART_TNT;
|
||||
case eTYPE_MUSHROOMCOW:
|
||||
return MUSHROOM_COW;
|
||||
case eTYPE_OCELOT:
|
||||
return OCELOT;
|
||||
case eTYPE_PAINTING:
|
||||
return PAINTING;
|
||||
case eTYPE_PIG:
|
||||
return PIG;
|
||||
case eTYPE_PIGZOMBIE:
|
||||
return PIG_ZOMBIE;
|
||||
case eTYPE_PLAYER:
|
||||
return PLAYER;
|
||||
case eTYPE_SERVERPLAYER:
|
||||
return PLAYER;
|
||||
case eTYPE_REMOTEPLAYER:
|
||||
return PLAYER;
|
||||
case eTYPE_LOCALPLAYER:
|
||||
return PLAYER;
|
||||
case eTYPE_PRIMEDTNT:
|
||||
return PRIMED_TNT;
|
||||
case eTYPE_SHEEP:
|
||||
return SHEEP;
|
||||
case eTYPE_SILVERFISH:
|
||||
return SILVERFISH;
|
||||
case eTYPE_SKELETON:
|
||||
return SKELETON;
|
||||
case eTYPE_SLIME:
|
||||
return SLIME;
|
||||
case eTYPE_SMALL_FIREBALL:
|
||||
return SMALL_FIREBALL;
|
||||
case eTYPE_SNOWBALL:
|
||||
return SNOWBALL;
|
||||
case eTYPE_SNOWMAN:
|
||||
return SNOWMAN;
|
||||
case eTYPE_SPIDER:
|
||||
return SPIDER;
|
||||
case eTYPE_THROWNPOTION:
|
||||
return SPLASH_POTION;
|
||||
case eTYPE_SQUID:
|
||||
return SQUID;
|
||||
case eTYPE_THROWNEXPBOTTLE:
|
||||
return THROWN_EXP_BOTTLE;
|
||||
case eTYPE_VILLAGER:
|
||||
return VILLAGER;
|
||||
case eTYPE_WITCH:
|
||||
return WITCH;
|
||||
case eTYPE_WITHERBOSS:
|
||||
return WITHER;
|
||||
case eTYPE_WITHER_SKULL:
|
||||
return WITHER_SKULL;
|
||||
case eTYPE_WOLF:
|
||||
return WOLF;
|
||||
case eTYPE_ZOMBIE:
|
||||
return ZOMBIE;
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int MapDamageCause(void *sourcePtr)
|
||||
{
|
||||
DamageSource *source = (DamageSource *)sourcePtr;
|
||||
const int CONTACT = 1, CUSTOM = 2, DROWNING = 3;
|
||||
const int ENTITY_ATTACK = 4, ENTITY_EXPLOSION = 5;
|
||||
const int FALL = 6, FALLING_BLOCK = 7, FIRE = 8, FIRE_TICK = 9;
|
||||
const int LAVA = 10, MAGIC = 12;
|
||||
const int PROJECTILE = 15, STARVATION = 16, SUFFOCATION = 17;
|
||||
const int CAUSE_VOID = 20, CAUSE_WITHER = 21;
|
||||
|
||||
if (source == nullptr)
|
||||
{
|
||||
return CUSTOM;
|
||||
}
|
||||
if (source == DamageSource::inFire)
|
||||
{
|
||||
return FIRE;
|
||||
}
|
||||
if (source == DamageSource::onFire)
|
||||
{
|
||||
return FIRE_TICK;
|
||||
}
|
||||
if (source == DamageSource::lava)
|
||||
{
|
||||
return LAVA;
|
||||
}
|
||||
if (source == DamageSource::inWall)
|
||||
{
|
||||
return SUFFOCATION;
|
||||
}
|
||||
if (source == DamageSource::drown)
|
||||
{
|
||||
return DROWNING;
|
||||
}
|
||||
if (source == DamageSource::starve)
|
||||
{
|
||||
return STARVATION;
|
||||
}
|
||||
if (source == DamageSource::cactus)
|
||||
{
|
||||
return CONTACT;
|
||||
}
|
||||
if (source == DamageSource::fall)
|
||||
{
|
||||
return FALL;
|
||||
}
|
||||
if (source == DamageSource::outOfWorld)
|
||||
{
|
||||
return CAUSE_VOID;
|
||||
}
|
||||
if (source == DamageSource::genericSource)
|
||||
{
|
||||
return CUSTOM;
|
||||
}
|
||||
if (source == DamageSource::magic)
|
||||
{
|
||||
return MAGIC;
|
||||
}
|
||||
if (source == DamageSource::wither)
|
||||
{
|
||||
return CAUSE_WITHER;
|
||||
}
|
||||
if (source == DamageSource::anvil)
|
||||
{
|
||||
return FALLING_BLOCK;
|
||||
}
|
||||
if (source == DamageSource::fallingBlock)
|
||||
{
|
||||
return FALLING_BLOCK;
|
||||
}
|
||||
|
||||
if (source->isExplosion())
|
||||
{
|
||||
return ENTITY_EXPLOSION;
|
||||
}
|
||||
if (source->isProjectile())
|
||||
{
|
||||
return PROJECTILE;
|
||||
}
|
||||
if (source->isMagic())
|
||||
{
|
||||
return MAGIC;
|
||||
}
|
||||
|
||||
if (dynamic_cast<EntityDamageSource *>(source) != nullptr)
|
||||
{
|
||||
return ENTITY_ATTACK;
|
||||
}
|
||||
|
||||
return CUSTOM;
|
||||
}
|
||||
}
|
||||
1140
Minecraft.Server/FourKitNatives.cpp
Normal file
1140
Minecraft.Server/FourKitNatives.cpp
Normal file
File diff suppressed because it is too large
Load diff
77
Minecraft.Server/FourKitNatives.h
Normal file
77
Minecraft.Server/FourKitNatives.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
namespace FourKitBridge
|
||||
{
|
||||
// core
|
||||
void __cdecl NativeDamagePlayer(int entityId, float amount);
|
||||
void __cdecl NativeSetPlayerHealth(int entityId, float health);
|
||||
void __cdecl NativeTeleportPlayer(int entityId, double x, double y, double z);
|
||||
void __cdecl NativeSetPlayerGameMode(int entityId, int gameMode);
|
||||
void __cdecl NativeBroadcastMessage(const char *utf8, int len);
|
||||
void __cdecl NativeSetFallDistance(int entityId, float distance);
|
||||
void __cdecl NativeGetPlayerSnapshot(int entityId, double *outData);
|
||||
void __cdecl NativeSendMessage(int entityId, const char *utf8, int len);
|
||||
void __cdecl NativeSetWalkSpeed(int entityId, float speed);
|
||||
void __cdecl NativeTeleportEntity(int entityId, int dimId, double x, double y, double z);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
void __cdecl NativeSetWorldTime(int dimId, int64_t time);
|
||||
void __cdecl NativeSetWeather(int dimId, int storm, int thundering, int thunderDuration);
|
||||
int __cdecl NativeCreateExplosion(int dimId, double x, double y, double z, float power, int setFire, int breakBlocks);
|
||||
int __cdecl NativeStrikeLightning(int dimId, double x, double y, double z, int effectOnly);
|
||||
int __cdecl NativeSetSpawnLocation(int dimId, int x, int y, int z);
|
||||
void __cdecl NativeDropItem(int dimId, double x, double y, double z, int itemId, int count, int auxValue, int naturally);
|
||||
|
||||
// plr
|
||||
void __cdecl NativeKickPlayer(int entityId, int reason);
|
||||
int __cdecl NativeBanPlayer(int entityId, const char *reasonUtf8, int reasonByteLen);
|
||||
int __cdecl NativeBanPlayerIp(int entityId, const char *reasonUtf8, int reasonByteLen);
|
||||
int __cdecl NativeGetPlayerAddress(int entityId, char *outIpBuf, int outIpBufSize, int *outPort);
|
||||
|
||||
// inv
|
||||
void __cdecl NativeGetPlayerInventory(int entityId, int *outData);
|
||||
void __cdecl NativeSetPlayerInventorySlot(int entityId, int slot, int itemId, int count, int aux);
|
||||
void __cdecl NativeGetContainerContents(int entityId, int *outData, int maxSlots);
|
||||
void __cdecl NativeSetContainerSlot(int entityId, int slot, int itemId, int count, int aux);
|
||||
void __cdecl NativeGetContainerViewerEntityIds(int entityId, int *outIds, int maxCount, int *outCount);
|
||||
void __cdecl NativeCloseContainer(int entityId);
|
||||
void __cdecl NativeOpenVirtualContainer(int entityId, int nativeType, const char *titleUtf8, int titleByteLen, int slotCount, int *itemsBuf);
|
||||
int __cdecl NativeGetItemMeta(int entityId, int slot, char *outBuf, int bufSize);
|
||||
void __cdecl NativeSetItemMeta(int entityId, int slot, const char *inBuf, int bufSize);
|
||||
void __cdecl NativeSetHeldItemSlot(int entityId, int slot);
|
||||
|
||||
// ent
|
||||
void __cdecl NativeSetSneaking(int entityId, int sneak);
|
||||
void __cdecl NativeSetVelocity(int entityId, double x, double y, double z);
|
||||
void __cdecl NativeSetAllowFlight(int entityId, int allowFlight);
|
||||
void __cdecl NativePlaySound(int entityId, int soundId, double x, double y, double z, float volume, float pitch);
|
||||
void __cdecl NativeSetSleepingIgnored(int entityId, int ignored);
|
||||
|
||||
// x[p&food
|
||||
void __cdecl NativeSetLevel(int entityId, int level);
|
||||
void __cdecl NativeSetExp(int entityId, float exp);
|
||||
void __cdecl NativeGiveExp(int entityId, int amount);
|
||||
void __cdecl NativeGiveExpLevels(int entityId, int amount);
|
||||
void __cdecl NativeSetFoodLevel(int entityId, int foodLevel);
|
||||
void __cdecl NativeSetSaturation(int entityId, float saturation);
|
||||
void __cdecl NativeSetExhaustion(int entityId, float exhaustion);
|
||||
|
||||
// particle
|
||||
void __cdecl NativeSpawnParticle(int entityId, int particleId, float x, float y, float z, float offsetX, float offsetY, float offsetZ, float speed, int count);
|
||||
|
||||
// vehicle
|
||||
int __cdecl NativeSetPassenger(int entityId, int passengerEntityId);
|
||||
int __cdecl NativeLeaveVehicle(int entityId);
|
||||
int __cdecl NativeEject(int entityId);
|
||||
int __cdecl NativeGetVehicleId(int entityId);
|
||||
int __cdecl NativeGetPassengerId(int entityId);
|
||||
void __cdecl NativeGetEntityInfo(int entityId, double *outData);
|
||||
}
|
||||
241
Minecraft.Server/FourKitRuntime.cpp
Normal file
241
Minecraft.Server/FourKitRuntime.cpp
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
#include "FourKitRuntime.h"
|
||||
#include "ServerLogger.h"
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <windows.h>
|
||||
|
||||
using ServerRuntime::LogError;
|
||||
|
||||
typedef void *hostfxr_handle;
|
||||
|
||||
typedef int(__cdecl *hostfxr_initialize_for_runtime_config_fn)(
|
||||
const wchar_t *runtime_config_path,
|
||||
const void *parameters,
|
||||
hostfxr_handle *host_context_handle);
|
||||
|
||||
enum hostfxr_delegate_type
|
||||
{
|
||||
hdt_com_activation = 0,
|
||||
hdt_load_in_memory_assembly = 1,
|
||||
hdt_winrt_activation = 2,
|
||||
hdt_com_register = 3,
|
||||
hdt_com_unregister = 4,
|
||||
hdt_load_assembly_and_get_function_pointer = 5,
|
||||
hdt_get_function_pointer = 6,
|
||||
};
|
||||
|
||||
typedef int(__cdecl *hostfxr_get_runtime_delegate_fn)(
|
||||
const hostfxr_handle host_context_handle,
|
||||
hostfxr_delegate_type type,
|
||||
void **delegate);
|
||||
|
||||
typedef int(__cdecl *hostfxr_close_fn)(const hostfxr_handle host_context_handle);
|
||||
|
||||
struct hostfxr_initialize_parameters
|
||||
{
|
||||
size_t size;
|
||||
const wchar_t *host_path;
|
||||
const wchar_t *dotnet_root;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
static hostfxr_initialize_for_runtime_config_fn s_initFn = nullptr;
|
||||
static hostfxr_get_runtime_delegate_fn s_getDelegateFn = nullptr;
|
||||
static hostfxr_close_fn s_closeFn = nullptr;
|
||||
static std::wstring s_dotnetRoot;
|
||||
|
||||
static std::wstring FindNet10SystemRoot()
|
||||
{
|
||||
std::vector<std::wstring> candidates;
|
||||
wchar_t envRoot[MAX_PATH] = {};
|
||||
DWORD len = GetEnvironmentVariableW(L"DOTNET_ROOT", envRoot, MAX_PATH);
|
||||
if (len > 0 && len < MAX_PATH)
|
||||
{
|
||||
candidates.push_back(std::wstring(envRoot));
|
||||
}
|
||||
candidates.push_back(L"C:\\Program Files\\dotnet");
|
||||
|
||||
for (const auto &root : candidates)
|
||||
{
|
||||
std::wstring fxrDir = root + L"\\host\\fxr";
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE h = FindFirstFileW((fxrDir + L"\\*").c_str(), &fd);
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bool has10 = false;
|
||||
do
|
||||
{
|
||||
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.cFileName[0] != L'.')
|
||||
{
|
||||
if (std::wstring(fd.cFileName).substr(0, 3) == L"10.")
|
||||
{
|
||||
has10 = true;
|
||||
}
|
||||
}
|
||||
} while (!has10 && FindNextFileW(h, &fd));
|
||||
FindClose(h);
|
||||
if (has10)
|
||||
{
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
return L"C:\\Program Files\\dotnet";
|
||||
}
|
||||
|
||||
static bool TryLoadHostfxrFromPath(const std::wstring &path)
|
||||
{
|
||||
HMODULE lib = LoadLibraryW(path.c_str());
|
||||
if (!lib)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
s_initFn = (hostfxr_initialize_for_runtime_config_fn)GetProcAddress(lib, "hostfxr_initialize_for_runtime_config");
|
||||
s_getDelegateFn = (hostfxr_get_runtime_delegate_fn)GetProcAddress(lib, "hostfxr_get_runtime_delegate");
|
||||
s_closeFn = (hostfxr_close_fn)GetProcAddress(lib, "hostfxr_close");
|
||||
|
||||
if (s_initFn && s_getDelegateFn && s_closeFn)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
s_initFn = nullptr;
|
||||
s_getDelegateFn = nullptr;
|
||||
s_closeFn = nullptr;
|
||||
FreeLibrary(lib);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool LoadHostfxr()
|
||||
{
|
||||
wchar_t exePath[MAX_PATH] = {};
|
||||
GetModuleFileNameW(NULL, exePath, MAX_PATH);
|
||||
std::wstring exeDir(exePath);
|
||||
size_t lastSlash = exeDir.find_last_of(L"\\/");
|
||||
if (lastSlash != std::wstring::npos)
|
||||
{
|
||||
exeDir = exeDir.substr(0, lastSlash);
|
||||
}
|
||||
|
||||
if (TryLoadHostfxrFromPath(exeDir + L"\\hostfxr.dll"))
|
||||
{
|
||||
s_dotnetRoot = FindNet10SystemRoot();
|
||||
return true;
|
||||
}
|
||||
|
||||
wchar_t dotnetRoot[MAX_PATH] = {};
|
||||
DWORD len = GetEnvironmentVariableW(L"DOTNET_ROOT", dotnetRoot, MAX_PATH);
|
||||
if (len == 0 || len >= MAX_PATH)
|
||||
{
|
||||
wcscpy_s(dotnetRoot, L"C:\\Program Files\\dotnet");
|
||||
}
|
||||
|
||||
std::wstring hostfxrDir = std::wstring(dotnetRoot) + L"\\host\\fxr";
|
||||
|
||||
WIN32_FIND_DATAW fd;
|
||||
HANDLE hFind = FindFirstFileW((hostfxrDir + L"\\*").c_str(), &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
std::wstring bestVersion;
|
||||
do
|
||||
{
|
||||
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && fd.cFileName[0] != L'.')
|
||||
{
|
||||
std::wstring ver(fd.cFileName);
|
||||
if (ver.substr(0, 3) == L"10." && ver > bestVersion)
|
||||
{
|
||||
bestVersion = ver;
|
||||
}
|
||||
}
|
||||
} while (FindNextFileW(hFind, &fd));
|
||||
FindClose(hFind);
|
||||
|
||||
if (!bestVersion.empty())
|
||||
{
|
||||
if (TryLoadHostfxrFromPath(hostfxrDir + L"\\" + bestVersion + L"\\hostfxr.dll"))
|
||||
{
|
||||
s_dotnetRoot = std::wstring(dotnetRoot);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogError("fourkit", "hostfxr.dll not found. Install the .NET 10 x64 runtime (https://aka.ms/dotnet/download) or copy hostfxr.dll from C:\\Program Files\\dotnet\\host\\fxr\\10.x.x\\ next to the server executable.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace FourKitBridge
|
||||
{
|
||||
bool LoadManagedRuntime(const wchar_t *runtimeConfigPath,
|
||||
const wchar_t *hostPath,
|
||||
load_assembly_fn *outLoadAssembly)
|
||||
{
|
||||
if (!LoadHostfxr())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
hostfxr_initialize_parameters initParams = {};
|
||||
initParams.size = sizeof(hostfxr_initialize_parameters);
|
||||
initParams.host_path = hostPath;
|
||||
initParams.dotnet_root = s_dotnetRoot.c_str();
|
||||
|
||||
hostfxr_handle ctx = nullptr;
|
||||
int rc = s_initFn(runtimeConfigPath, &initParams, &ctx);
|
||||
if (rc != 0 || ctx == nullptr)
|
||||
{
|
||||
char msg[256];
|
||||
sprintf_s(msg, "hostfxr_initialize_for_runtime_config failed (0x%08X). Check runtimeconfig.json path.", rc);
|
||||
LogError("fourkit", msg);
|
||||
if (ctx)
|
||||
{
|
||||
s_closeFn(ctx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
load_assembly_fn loadAssembly = nullptr;
|
||||
rc = s_getDelegateFn(ctx, hdt_load_assembly_and_get_function_pointer, (void **)&loadAssembly);
|
||||
s_closeFn(ctx);
|
||||
|
||||
if (rc != 0 || loadAssembly == nullptr)
|
||||
{
|
||||
LogError("fourkit", "Failed to get load_assembly_and_get_function_pointer delegate.");
|
||||
return false;
|
||||
}
|
||||
|
||||
*outLoadAssembly = loadAssembly;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetManagedEntryPoint(load_assembly_fn loadAssembly,
|
||||
const wchar_t *assemblyPath,
|
||||
const wchar_t *typeName,
|
||||
const wchar_t *methodName,
|
||||
void **outFnPtr)
|
||||
{
|
||||
int rc = loadAssembly(
|
||||
assemblyPath,
|
||||
typeName,
|
||||
methodName,
|
||||
UNMANAGEDCALLERSONLY_METHOD,
|
||||
nullptr,
|
||||
outFnPtr);
|
||||
|
||||
if (rc != 0 || *outFnPtr == nullptr)
|
||||
{
|
||||
char methodNarrow[256];
|
||||
sprintf_s(methodNarrow, "%S::%S", typeName, methodName);
|
||||
LogError("fourkit", (std::string("Failed to resolve managed entry point: ") + methodNarrow).c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
24
Minecraft.Server/FourKitRuntime.h
Normal file
24
Minecraft.Server/FourKitRuntime.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#define UNMANAGEDCALLERSONLY_METHOD ((const wchar_t *)-1)
|
||||
|
||||
namespace FourKitBridge
|
||||
{
|
||||
typedef int(__stdcall *load_assembly_fn)(
|
||||
const wchar_t *assembly_path,
|
||||
const wchar_t *type_name,
|
||||
const wchar_t *method_name,
|
||||
const wchar_t *delegate_type_name,
|
||||
void *reserved,
|
||||
void **delegate);
|
||||
|
||||
bool LoadManagedRuntime(const wchar_t *runtimeConfigPath,
|
||||
const wchar_t *hostPath,
|
||||
load_assembly_fn *outLoadAssembly);
|
||||
|
||||
bool GetManagedEntryPoint(load_assembly_fn loadAssembly,
|
||||
const wchar_t *assemblyPath,
|
||||
const wchar_t *typeName,
|
||||
const wchar_t *methodName,
|
||||
void **outFnPtr);
|
||||
}
|
||||
|
|
@ -522,6 +522,11 @@ set(_MINECRAFT_SERVER_COMMON_SERVER
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/WorldManager.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/FourKitBridge.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/FourKitBridge.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/FourKitMappers.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/FourKitNatives.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/FourKitNatives.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/FourKitRuntime.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/FourKitRuntime.h"
|
||||
)
|
||||
source_group("Server" FILES ${_MINECRAFT_SERVER_COMMON_SERVER})
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue