mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-05-12 12:13:51 +00:00
Merge branch 'feature/plugin-api' of github.com:sylvessa/MinecraftConsoles into feature/plugin-api
This commit is contained in:
commit
8e66b2c19e
13 changed files with 570 additions and 5 deletions
|
|
@ -63,6 +63,10 @@
|
|||
#include "Durango\Network\NetworkPlayerDurango.h"
|
||||
#endif
|
||||
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
#include "..\Minecraft.Server\FourKitNatives.h"
|
||||
#endif
|
||||
|
||||
#define DEBUG_SERVER_DONT_SPAWN_MOBS 0
|
||||
|
||||
//4J Added
|
||||
|
|
@ -2208,6 +2212,12 @@ void MinecraftServer::tick()
|
|||
connection->tick();
|
||||
PIXEndNamedEvent();
|
||||
|
||||
#if defined(MINECRAFT_SERVER_BUILD)
|
||||
PIXBeginNamedEvent(0, "FourKit Scheduler tick");
|
||||
FourKitBridge::ServerTickCallback(tickCount);
|
||||
PIXEndNamedEvent();
|
||||
#endif
|
||||
|
||||
// 4J - removed
|
||||
#if 0
|
||||
for (size_t i = 0; i < tickables.size(); i++) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Minecraft.Server.FourKit.Entity;
|
|||
using Minecraft.Server.FourKit.Event;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
using Minecraft.Server.FourKit.Plugin;
|
||||
using Minecraft.Server.FourKit.Scheduler;
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the FourKit plugin API.
|
||||
|
|
@ -388,4 +389,6 @@ public static class FourKit
|
|||
/// </summary>
|
||||
/// <param name="plugin">Plugin to disable.</param>
|
||||
public static void disablePlugin(ServerPlugin plugin) => FourKitHost.s_loader?.DisablePlugin(plugin);
|
||||
|
||||
public static FourKitScheduler getScheduler() => FourKitHost.getScheduler();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,24 @@
|
|||
using Minecraft.Server.FourKit.Scheduler;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Minecraft.Server.FourKit;
|
||||
|
||||
public static partial class FourKitHost
|
||||
{
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void SetSchedulerCallbacks(IntPtr add, IntPtr remove)
|
||||
{
|
||||
try
|
||||
{
|
||||
NativeBridge.SetSchedulerCallbacks(add, remove);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"SetSchedulerCallbacks error: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -190,6 +190,19 @@ public static partial class FourKitHost
|
|||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static void FireSchedulerCallback(int currentTick) {
|
||||
try
|
||||
{
|
||||
FourKit.getScheduler().update(currentTick);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ServerLog.Error("fourkit", $"FireSchedulerCallback error: {ex}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
public static int FirePlayerMove(int entityId,
|
||||
double fromX, double fromY, double fromZ,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Entity;
|
||||
using Minecraft.Server.FourKit.Event.Inventory;
|
||||
using Minecraft.Server.FourKit.Inventory;
|
||||
using Minecraft.Server.FourKit.Scheduler;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Minecraft.Server.FourKit;
|
||||
|
||||
public static partial class FourKitHost
|
||||
{
|
||||
internal static PluginLoader? s_loader;
|
||||
internal static FourKitScheduler? s_scheduler;
|
||||
|
||||
public static IReadOnlyList<Plugin.ServerPlugin> getLoadedPlugins() => s_loader?.Plugins ?? [];
|
||||
|
||||
|
|
@ -16,6 +18,9 @@ public static partial class FourKitHost
|
|||
{
|
||||
try
|
||||
{
|
||||
ServerLog.Info("fourkit", "Initializing Scheduler...");
|
||||
s_scheduler = new FourKitScheduler();
|
||||
|
||||
ServerLog.Info("fourkit", "Initializing plugin system...");
|
||||
|
||||
string pluginsDir = Path.Combine(AppContext.BaseDirectory, "plugins");
|
||||
|
|
@ -47,6 +52,17 @@ public static partial class FourKitHost
|
|||
}
|
||||
}
|
||||
|
||||
internal static FourKitScheduler getScheduler()
|
||||
{
|
||||
if (s_scheduler == null)
|
||||
{
|
||||
ServerLog.Warn("fourkit", "Scheduler accessed before initialization. Initializing now...");
|
||||
s_scheduler = new FourKitScheduler();
|
||||
}
|
||||
|
||||
return s_scheduler;
|
||||
}
|
||||
|
||||
|
||||
private static Guid ParseOrHashGuid(string s)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -236,6 +236,13 @@ internal static class NativeBridge
|
|||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void NativeSetBiomeIdDelegate(int dimId, int x, int z, int biomeId);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void NativeAddSchedulerDelegate(int taskid, int startDelay, int runCooldown);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
internal delegate void NativeRemoveSchedulerDelegate(int taskid);
|
||||
|
||||
internal static NativeDamageDelegate? DamagePlayer;
|
||||
internal static NativeSetHealthDelegate? SetPlayerHealth;
|
||||
internal static NativeTeleportDelegate? TeleportPlayer;
|
||||
|
|
@ -315,6 +322,15 @@ internal static class NativeBridge
|
|||
internal static NativeGetBiomeIdDelegate? GetBiomeId;
|
||||
internal static NativeSetBiomeIdDelegate? SetBiomeId;
|
||||
|
||||
internal static NativeAddSchedulerDelegate? AddScheduler;
|
||||
internal static NativeRemoveSchedulerDelegate? RemoveScheduler;
|
||||
|
||||
internal static void SetSchedulerCallbacks(IntPtr addScheduler, IntPtr removeScheduler)
|
||||
{
|
||||
AddScheduler = Marshal.GetDelegateForFunctionPointer<NativeAddSchedulerDelegate>(addScheduler);
|
||||
RemoveScheduler = Marshal.GetDelegateForFunctionPointer<NativeRemoveSchedulerDelegate>(removeScheduler);
|
||||
}
|
||||
|
||||
internal static void SetCallbacks(IntPtr damage, IntPtr setHealth, IntPtr teleport, IntPtr setGameMode, IntPtr broadcastMessage, IntPtr setFallDistance, IntPtr getPlayerSnapshot, IntPtr sendMessage, IntPtr setWalkSpeed, IntPtr teleportEntity)
|
||||
{
|
||||
DamagePlayer = Marshal.GetDelegateForFunctionPointer<NativeDamageDelegate>(damage);
|
||||
|
|
|
|||
245
Minecraft.Server.FourKit/Scheduler/FourKitScheduler.cs
Normal file
245
Minecraft.Server.FourKit/Scheduler/FourKitScheduler.cs
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
using Minecraft.Server.FourKit.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Scheduler
|
||||
{
|
||||
public class FourKitScheduler
|
||||
{
|
||||
private Dictionary<int, FourKitTask> _taskInstanceMap = new Dictionary<int, FourKitTask>();
|
||||
private Dictionary<int, Action> _taskActionMap = new Dictionary<int, Action>();
|
||||
//temp task based on about intmax / 3, leaves 715m (715827882) ids for real tasks and 1.4b(1431655765) for temp tasks
|
||||
//this is done to avoid needing to cleanup existing task ids, could be handled
|
||||
private int _nextTempTaskId = 715827882;
|
||||
private int _nextTaskId = 0;
|
||||
|
||||
private int _lastTick = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Removes all tasks from the scheduler.
|
||||
/// </summary>
|
||||
public void cancelAllTasks()
|
||||
{
|
||||
foreach (var task in _taskInstanceMap.Values)
|
||||
{
|
||||
NativeBridge.RemoveScheduler?.Invoke(task.getTaskId());
|
||||
}
|
||||
|
||||
_taskInstanceMap.Clear();
|
||||
_taskActionMap.Clear();
|
||||
|
||||
_nextTempTaskId = 715827882;
|
||||
_nextTaskId = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes task from scheduler.
|
||||
/// </summary>
|
||||
/// <param name="taskId">Id number of task to be removed.</param>
|
||||
public void cancelTask(int taskId)
|
||||
{
|
||||
if (_taskInstanceMap.ContainsKey(taskId))
|
||||
{
|
||||
NativeBridge.RemoveScheduler?.Invoke(taskId);
|
||||
_taskInstanceMap.Remove(taskId);
|
||||
_taskActionMap.Remove(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all tasks associated with a particular plugin from the scheduler.
|
||||
/// </summary>
|
||||
/// <param name="plugin">Owner of tasks to be removed.</param>
|
||||
public void cancelTasks(ServerPlugin plugin)
|
||||
{
|
||||
List<int> tasksToRemove = new List<int>();
|
||||
|
||||
foreach (var task in _taskInstanceMap.Values)
|
||||
{
|
||||
if (task.getOwner() == plugin)
|
||||
{
|
||||
NativeBridge.RemoveScheduler?.Invoke(task.getTaskId());
|
||||
tasksToRemove.Add(task.getTaskId());
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var taskId in tasksToRemove)
|
||||
{
|
||||
_taskInstanceMap.Remove(taskId);
|
||||
_taskActionMap.Remove(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all pending tasks. The ordering of the tasks is not related to their order of execution.
|
||||
/// </summary>
|
||||
/// <returns>Active workers.</returns>
|
||||
public List<FourKitTask> getPendingTasks()
|
||||
{
|
||||
return new List<FourKitTask>(_taskInstanceMap.Values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the task currently running.
|
||||
///
|
||||
/// A repeating task might not be running currently, but will be running in the future.
|
||||
/// A task that has finished, and does not repeat, will not be running ever again.
|
||||
///
|
||||
/// Explicitly, a task is running if there exists a thread for it, and that thread is alive.
|
||||
/// </summary>
|
||||
/// <param name="taskId">The task to check.</param>
|
||||
/// <returns>If the task is currently running.</returns>
|
||||
public bool isCurrentlyRunning(int taskId)
|
||||
{
|
||||
if (_taskInstanceMap.ContainsKey(taskId))
|
||||
{
|
||||
return _taskInstanceMap[taskId].startedRunning;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the task queued to be run later.
|
||||
///
|
||||
/// If a repeating task is currently running, it might not be queued now but could be in the future.
|
||||
/// A task that is not queued, and not running, will not be queued again.
|
||||
/// </summary>
|
||||
/// <param name="taskId">The task to check.</param>
|
||||
/// <returns>If the task is queued to be run.</returns>
|
||||
public bool isQueued(int taskId)
|
||||
{
|
||||
if (_taskInstanceMap.ContainsKey(taskId))
|
||||
{
|
||||
return !_taskInstanceMap[taskId].startedRunning;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a task that will run on the next server tick.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The reference to the plugin scheduling task.</param>
|
||||
/// <param name="task">The task to be run.</param>
|
||||
/// <returns>A task that contains the id number.</returns>
|
||||
/// <exception cref="ArgumentNullException">If plugin is null.</exception>
|
||||
/// <exception cref="ArgumentNullException">If task is null.</exception>
|
||||
public FourKitTask runTask(ServerPlugin plugin, Action task)
|
||||
{
|
||||
FourKitTask fourKitTask = new FourKitTask(plugin, _nextTempTaskId++, 0, -1);
|
||||
|
||||
startTask(fourKitTask, task);
|
||||
|
||||
return fourKitTask;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a task that will run after the specified number of server ticks.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The reference to the plugin scheduling task.</param>
|
||||
/// <param name="task">The task to be run.</param>
|
||||
/// <param name="delay">The ticks to wait before running the task.</param>
|
||||
/// <returns>A task that contains the id number.</returns>
|
||||
/// <exception cref="ArgumentNullException">If plugin is null.</exception>
|
||||
/// <exception cref="ArgumentNullException">If task is null.</exception>
|
||||
public FourKitTask runTaskLater(ServerPlugin plugin, Action task, int delay)
|
||||
{
|
||||
FourKitTask fourKitTask = new FourKitTask(plugin, _nextTempTaskId++, delay, -1);
|
||||
|
||||
startTask(fourKitTask, task);
|
||||
|
||||
return fourKitTask;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a task that will repeatedly run until cancelled, starting after the specified number of server ticks.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The reference to the plugin scheduling task.</param>
|
||||
/// <param name="task">The task to be run.</param>
|
||||
/// <param name="delay">The ticks to wait before running the task.</param>
|
||||
/// <param name="period">The ticks to wait between runs.</param>
|
||||
/// <returns>A task that contains the id number.</returns>
|
||||
/// <exception cref="ArgumentNullException">If plugin is null.</exception>
|
||||
/// <exception cref="ArgumentNullException">If task is null.</exception>
|
||||
public FourKitTask runTaskTimer(ServerPlugin plugin, Action task, int delay, int period)
|
||||
{
|
||||
FourKitTask fourKitTask = new FourKitTask(plugin, _nextTempTaskId++, delay, period);
|
||||
|
||||
startTask(fourKitTask, task);
|
||||
|
||||
return fourKitTask;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts tracking a task instance and registers it with the native scheduler bridge.
|
||||
/// </summary>
|
||||
/// <param name="task">The task instance to schedule.</param>
|
||||
/// <param name="action">The callback action executed when the task runs.</param>
|
||||
internal void startTask(FourKitTask task, Action action)
|
||||
{
|
||||
task.startedRunning = true;
|
||||
_taskInstanceMap[task.getTaskId()] = task;
|
||||
_taskActionMap[task.getTaskId()] = action;
|
||||
NativeBridge.AddScheduler?.Invoke(task.getTaskId(), task.startDelay, task.runCooldown);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates scheduled tasks for the current server tick and runs due task callbacks.
|
||||
/// </summary>
|
||||
/// <param name="currentTick">The current server tick.</param>
|
||||
internal void update(int currentTick)
|
||||
{
|
||||
if (_lastTick == -1) _lastTick = currentTick;
|
||||
List<int> tasksToRemove = new List<int>();
|
||||
|
||||
foreach (var task in _taskInstanceMap.Values)
|
||||
{
|
||||
if (!task.shouldRun)
|
||||
{
|
||||
tasksToRemove.Add(task.getTaskId());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (task.startDelay > 0)
|
||||
{
|
||||
task.startDelay -= (currentTick - _lastTick);
|
||||
|
||||
if (task.startDelay <= 0)
|
||||
{
|
||||
task.startDelay = 0;
|
||||
_taskActionMap[task.getTaskId()]?.Invoke();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (task.runCooldown == -1)
|
||||
{
|
||||
task.lastRunTick = currentTick;
|
||||
_taskActionMap[task.getTaskId()]?.Invoke();
|
||||
tasksToRemove.Add(task.getTaskId());
|
||||
}
|
||||
else
|
||||
{
|
||||
int lastTaskTick = task.lastRunTick;
|
||||
if (lastTaskTick == -1 || (lastTaskTick + task.runCooldown) <= currentTick)
|
||||
{
|
||||
task.lastRunTick = currentTick;
|
||||
_taskActionMap[task.getTaskId()]?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var taskId in tasksToRemove)
|
||||
{
|
||||
_taskInstanceMap.Remove(taskId);
|
||||
_taskActionMap.Remove(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
52
Minecraft.Server.FourKit/Scheduler/FourKitTask.cs
Normal file
52
Minecraft.Server.FourKit/Scheduler/FourKitTask.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
using Minecraft.Server.FourKit.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Minecraft.Server.FourKit.Scheduler
|
||||
{
|
||||
public class FourKitTask
|
||||
{
|
||||
private ServerPlugin owner;
|
||||
private int taskId;
|
||||
internal bool shouldRun = true;
|
||||
|
||||
internal int startDelay;
|
||||
internal int runCooldown;
|
||||
internal int lastRunTick = -1;
|
||||
internal bool startedRunning = false;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new task instance with owner, task id, start delay, and run cooldown.
|
||||
/// </summary>
|
||||
/// <param name="owner">The plugin that owns this task.</param>
|
||||
/// <param name="taskId">Task id number.</param>
|
||||
/// <param name="startDelay">Delay in server ticks before executing the task.</param>
|
||||
/// <param name="runCooldown">Period in server ticks between runs, or -1 for one-shot tasks.</param>
|
||||
internal FourKitTask(ServerPlugin owner, int taskId, int startDelay, int runCooldown)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.taskId = taskId;
|
||||
this.startDelay = startDelay;
|
||||
this.runCooldown = runCooldown;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will attempt to cancel this task.
|
||||
/// </summary>
|
||||
public void cancel() { shouldRun = false; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Plugin that owns this task.
|
||||
/// </summary>
|
||||
/// <returns>The Plugin that owns the task.</returns>
|
||||
public ServerPlugin getOwner() { return owner; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the taskId for the task.
|
||||
/// </summary>
|
||||
/// <returns>Task id number.</returns>
|
||||
public int getTaskId() { return taskId; }
|
||||
|
||||
}
|
||||
}
|
||||
98
Minecraft.Server.FourKit/docs/scheduler-programming.md
Normal file
98
Minecraft.Server.FourKit/docs/scheduler-programming.md
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
@page scheduler-programming Scheduler Programming
|
||||
|
||||
@section introduction Introduction
|
||||
Usually when we code in FourKit, everything is ran linearly. Despite this you may wish to schedule some code to be executed at a later point of time.
|
||||
|
||||
Do NOT use the built in C# Thread system, it is not safe for FourKit.
|
||||
|
||||
@section getting_started Getting Started
|
||||
|
||||
To get started we either need the FourKitScheduler instance. You can get this from the server instance.
|
||||
```csharp
|
||||
FourKitScheduler scheduler = FourKit.getScheduler();
|
||||
```
|
||||
|
||||
When scheduling a task, you will also need to pass your main plugin class instance. Here is an example of how it can be done:
|
||||
|
||||
```csharp
|
||||
public class ExampleOne
|
||||
{
|
||||
// you can also use a getter
|
||||
public static ExampleOne Instance { get; private set; }
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
}
|
||||
// then
|
||||
public class Other
|
||||
{
|
||||
private readonly ExampleOne plugin = ExampleOne.Instance;
|
||||
}
|
||||
```
|
||||
|
||||
@section scheduling_delayed_task Scheduling a Delayed Task
|
||||
|
||||
The scheduling itself is based on ticks, the Minecraft time unit. 1 tick = 0.05 seconds or 1 second = 20 ticks.
|
||||
|
||||
Let's say you want to schedule a task to run 30 seconds later which broadcasts a message:
|
||||
|
||||
```csharp
|
||||
FourKitScheduler scheduler = FourKit.getScheduler();
|
||||
|
||||
scheduler.runTaskLater(plugin, () => {
|
||||
FourKit.broadcastMessage("Mooooo!");
|
||||
}, 20 * 30 /*<-- the delay */);
|
||||
```
|
||||
|
||||
@section scheduling_repeating_task Scheduling a Repeating Task
|
||||
|
||||
Repeating tasks are tasks that can reschedule themselves.
|
||||
|
||||
Let's say you want to schedule a task to run 10 seconds later then after that it should repeat itself a finite amount of times with an interval of 5 seconds between each consecutive run:
|
||||
|
||||
```csharp
|
||||
FourKitScheduler scheduler = FourKit.getScheduler();
|
||||
|
||||
scheduler.runTaskTimer(plugin, () => {
|
||||
FourKit.broadcastMessage("Mooooo!");
|
||||
}, 20 * 10 /*<-- the initial delay */, 20 * 5 /*<-- the interval */);
|
||||
```
|
||||
|
||||
@section run_task_next_tick Running a Task on the Next Tick
|
||||
|
||||
Sometimes we just want to run some code on the next tick:
|
||||
|
||||
```csharp
|
||||
FourKitScheduler scheduler = FourKit.getScheduler();
|
||||
|
||||
scheduler.runTask(plugin, () => {
|
||||
FourKit.broadcastMessage("Mooooo again!");
|
||||
});
|
||||
```
|
||||
|
||||
@section canceling_tasks Canceling Tasks
|
||||
|
||||
Sometimes we want to just cancel a task!
|
||||
|
||||
```csharp
|
||||
FourKitScheduler scheduler = FourKit.getScheduler();
|
||||
|
||||
// Cancel outside
|
||||
FourKitTask task = scheduler.runTaskLater(plugin, () => {
|
||||
FourKit.broadcastMessage("Mooooo again!");
|
||||
}, 20 * 60);
|
||||
|
||||
// Cancel inside
|
||||
scheduler.runTaskTimer(plugin, () => {
|
||||
if (FourKit.getOnlinePlayers().Count == 0) {
|
||||
task.cancel(); // <--
|
||||
return;
|
||||
}
|
||||
FourKit.broadcastMessage("Mooooo again!");
|
||||
}, 0, 20 * 60);
|
||||
|
||||
// then
|
||||
task.cancel(); // <--
|
||||
```
|
||||
|
|
@ -30,6 +30,8 @@ typedef int(__stdcall *fn_fire_player_move)(int entityId,
|
|||
double fromX, double fromY, double fromZ,
|
||||
double toX, double toY, double toZ,
|
||||
double *outCoords);
|
||||
typedef void(__stdcall* fn_set_scheduler_callbacks)(void* add, void* remove);
|
||||
typedef void(__stdcall* fn_fire_scheduler_callback)(int currentTick);
|
||||
typedef void(__stdcall *fn_set_native_callbacks)(void *damage, void *setHealth, void *teleport, void *setGameMode, void *broadcastMessage, void *setFallDistance, void *getPlayerSnapshot, void *sendMessage, void *setWalkSpeed, void *teleportEntity);
|
||||
typedef void(__stdcall *fn_set_world_callbacks)(void *getTileId, void *getTileData, void *setTile, void *setTileData, void *breakBlock, void *getHighestBlockY, void *getWorldInfo, void *setWorldTime, void *setWeather, void *createExplosion, void *strikeLightning, void *setSpawnLocation, void *dropItem);
|
||||
typedef void(__stdcall *fn_update_entity_id)(int oldEntityId, int newEntityId);
|
||||
|
|
@ -128,6 +130,8 @@ static fn_update_entity_id s_managedUpdateEntityId = nullptr;
|
|||
static fn_fire_player_quit s_managedFireQuit = nullptr;
|
||||
static fn_fire_player_kick s_managedFireKick = nullptr;
|
||||
static fn_fire_player_move s_managedFireMove = nullptr;
|
||||
static fn_set_scheduler_callbacks s_managedSetSchedulerCallbacks = nullptr;
|
||||
static fn_fire_scheduler_callback s_managedFireSchedulerCallback = nullptr;
|
||||
static fn_set_native_callbacks s_managedSetCallbacks = nullptr;
|
||||
static fn_set_world_callbacks s_managedSetWorldCallbacks = nullptr;
|
||||
static fn_fire_structure_grow s_managedFireStructureGrow = nullptr;
|
||||
|
|
@ -211,6 +215,8 @@ void Initialize()
|
|||
{L"FirePlayerQuit", (void **)&s_managedFireQuit},
|
||||
{L"FirePlayerKick", (void **)&s_managedFireKick},
|
||||
{L"FirePlayerMove", (void **)&s_managedFireMove},
|
||||
{L"SetSchedulerCallbacks", (void**)&s_managedSetSchedulerCallbacks},
|
||||
{L"FireSchedulerCallback", (void**)&s_managedFireSchedulerCallback},
|
||||
{L"SetNativeCallbacks", (void **)&s_managedSetCallbacks},
|
||||
{L"SetWorldCallbacks", (void **)&s_managedSetWorldCallbacks},
|
||||
{L"UpdatePlayerEntityId", (void **)&s_managedUpdateEntityId},
|
||||
|
|
@ -270,9 +276,11 @@ void Initialize()
|
|||
return;
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
s_managedInit();
|
||||
s_managedSetSchedulerCallbacks(
|
||||
(void*)&NativeAddScheduler,
|
||||
(void*)&NativeRemoveScheduler
|
||||
);
|
||||
|
||||
s_managedSetCallbacks(
|
||||
(void *)&NativeDamagePlayer,
|
||||
|
|
@ -375,6 +383,10 @@ void Initialize()
|
|||
(void *)&NativeGetWorldEntities,
|
||||
(void *)&NativeGetChunkEntities);
|
||||
|
||||
//we should init after setting callbacks so we have access inside the plugins on enable
|
||||
s_initialized = true;
|
||||
s_managedInit();
|
||||
|
||||
LogInfo("fourkit", "FourKit initialized successfully.");
|
||||
}
|
||||
|
||||
|
|
@ -515,6 +527,16 @@ void UpdatePlayerEntityId(int oldEntityId, int newEntityId)
|
|||
LogDebugf("fourkit", "UpdatePlayerEntityId: %d -> %d", oldEntityId, newEntityId);
|
||||
}
|
||||
|
||||
void FireSchedulerCallback(int currentTick)
|
||||
{
|
||||
if (!s_initialized || !s_managedFireSchedulerCallback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s_managedFireSchedulerCallback(currentTick);
|
||||
}
|
||||
|
||||
bool FirePlayerMove(int entityId,
|
||||
double fromX, double fromY, double fromZ,
|
||||
double toX, double toY, double toZ,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace FourKitBridge
|
|||
bool FirePlayerQuit(int entityId);
|
||||
bool FirePlayerKick(int entityId, int disconnectReason,
|
||||
std::wstring &outLeaveMessage);
|
||||
void FireSchedulerCallback(int currentTick);
|
||||
bool FirePlayerMove(int entityId,
|
||||
double fromX, double fromY, double fromZ,
|
||||
double toX, double toY, double toZ,
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include "Common\NetworkUtils.h"
|
||||
#include "ServerLogManager.h"
|
||||
#include "../Minecraft.World/ItemInstance.cpp"
|
||||
#include <mutex>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -104,12 +105,79 @@ class VirtualContainer : public SimpleContainer
|
|||
return m_containerType;
|
||||
}
|
||||
};
|
||||
class NativeFourKitTask;
|
||||
|
||||
static int64_t STATIC_lastTick = -1;
|
||||
static std::unordered_map<int, std::shared_ptr<NativeFourKitTask>> _taskCache;
|
||||
static std::mutex _taskMutex;
|
||||
|
||||
class NativeFourKitTask {
|
||||
public:
|
||||
int startDelay;
|
||||
int runCooldown;
|
||||
|
||||
int lastRunTick;
|
||||
|
||||
NativeFourKitTask(int _startDelay, int _runCooldown) : startDelay(_startDelay), runCooldown(_runCooldown), lastRunTick(-1) {};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace FourKitBridge
|
||||
{
|
||||
void __cdecl NativeDamagePlayer(int entityId, float amount)
|
||||
|
||||
void __cdecl NativeAddScheduler(int taskid, int startDelay, int runCooldown)
|
||||
{
|
||||
std::lock_guard<std::mutex> g(_taskMutex);
|
||||
_taskCache.emplace(taskid, std::make_shared<NativeFourKitTask>(startDelay, runCooldown));
|
||||
}
|
||||
|
||||
void __cdecl NativeRemoveScheduler(int taskid)
|
||||
{
|
||||
std::lock_guard<std::mutex> g(_taskMutex);
|
||||
auto it = _taskCache.find(taskid);
|
||||
|
||||
if (it != _taskCache.end()) {
|
||||
_taskCache.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void ServerTickCallback(int currentTick)
|
||||
{
|
||||
bool callManagedFunction = false;
|
||||
|
||||
if (STATIC_lastTick == -1) {
|
||||
callManagedFunction = true;
|
||||
STATIC_lastTick = currentTick;
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> g(_taskMutex);
|
||||
for (const auto& [taskid, task] : _taskCache)
|
||||
{
|
||||
NativeFourKitTask* taskPointer = task.get();
|
||||
if (taskPointer->startDelay > 0) {
|
||||
taskPointer->startDelay -= (currentTick - STATIC_lastTick);
|
||||
|
||||
if (taskPointer->startDelay <= 0) {
|
||||
callManagedFunction = true; //make c# update the tasks so its not queued anymore but now its running
|
||||
taskPointer->startDelay = 0; //ensure it stays 0
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int lastTaskTick = taskPointer->lastRunTick;
|
||||
if (lastTaskTick == -1 || (lastTaskTick + taskPointer->runCooldown) <= currentTick) {
|
||||
callManagedFunction = true;
|
||||
taskPointer->lastRunTick = currentTick;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (callManagedFunction) FireSchedulerCallback(currentTick);
|
||||
STATIC_lastTick = currentTick;
|
||||
}
|
||||
void __cdecl NativeDamagePlayer(int entityId, float amount)
|
||||
{
|
||||
auto player = FindPlayer(entityId);
|
||||
if (player)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
|
||||
namespace FourKitBridge
|
||||
{
|
||||
//scheduler
|
||||
void __cdecl NativeAddScheduler(int taskid, int startDelay, int runCooldown);
|
||||
void __cdecl NativeRemoveScheduler(int taskid);
|
||||
|
||||
void ServerTickCallback(int currentTick);
|
||||
|
||||
// core
|
||||
void __cdecl NativeDamagePlayer(int entityId, float amount);
|
||||
void __cdecl NativeSetPlayerHealth(int entityId, float health);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue