Jump to content

Exact Event Control API

Pending 3.2.2

Moose
Moose

Posted

Subject

Supported API for named spawn and exact-event despawn/deadline control in 3.2.2

Message

Hi nivex,

We are building a small external uMod controller for Raidable Bases 3.2.2 without modifying or redistributing your source.

We need to:

  1. Queue exactly one named manual base at a selected difficulty and reliably correlate the resulting canonical event ID.
  2. Despawn one exact active event, or update its despawn deadline, using the canonical ID exposed by GetAllEvents.

The public lifecycle/read APIs cover observation and reconciliation. The configured server-console command appears suitable for requesting a named manual event, but it does not synchronously return the resulting event ID. The available admin despawn command selects the nearest event rather than accepting an event ID.

We will not call private methods, use reflection, teleport an administrator to select a raid, or delete event entities ourselves.

Could you please confirm the supported Plugin.Call/API signatures for:

  • spawning one named manual event and correlating its ID; and
  • despawning or updating the deadline of one exact event by ID?

If those operations are not currently exposed, confirmation of that would also help us keep the integration safe.

Versions:

  • Raidable Bases 3.2.2
  • CopyPaste 4.3.0
  • Oxide/uMod target

Thank you.

nivex

Posted (edited)

heya,

Most of this added in the next update:

  • All hooks are updated to provide an event ID
  • A new hook for OnRaidableBaseStart(Guid eventId, Vector3 pos, float protectionRadius, int level, string baseName, bool allowPVP, ulong ownerId, BasePlayer owner) is called before an event pastes (OnRaidableBaseStarted has a different signature which is documented, and is called when events become raidable)
  • A new hook for OnRaidableBaseEnded(Guid eventId, Vector3 pos, float protectionRadius, int level, string baseName, bool allowPVP, ulong ownerId, BasePlayer owner) which matches the Start parameters
  • A new hook for OnRaidableBaseLocationChanged(Guid guid, Vector3 previous, Vector3 current) when its position is updated (this happens exactly once for bases not copied at their center)
  • A new GetAllEvents API to compliment this

All of these ensure events can be tracked without issue

No despawn API will be exposed, sorry.

SpawnRandomBase exposes API for spawning manual events already, and will remain undocumented. Here is an example of how to use it, along with comments. I won't expose more than this, sorry:

        private void SpawnRandomBaseEvent(string baseName, Vector3 position, int level, int type, bool bypassDisabledProfiles)
        {
            // Deliberately made with certain limitations:
            // baseName: Provide a copypaste filename from your profiles to spawn that base, or provide null to spawn random.
            // position: The position where the event will paste, bases not copied properly will have their position recentere and this one-time update is called via OnRaidableBaseLocationChanged hook.
            // level: The difficulty level found in your profiles. Pass -1 to be random. Defaults: Easy=0,Medium=1,Hard=1,Expert=2,Nightmare=4
            // type: Valid types are Manual=1, Scheduled=2, Maintained=4, do not pass 0 or 3
            // bypassDisabledProfiles: Profiles that are disabled cannot be spawned unless true is passed
            Plugin rb = plugins.Find("RaidableBases");
            if (rb == null || !rb.IsLoaded)
            {
                Puts("RaidableBases not found or not loaded.");
                return;
            }
            object result = rb.Call("SpawnRandomBase", baseName, position, level, type, bypassDisabledProfiles);
            if (result is true) return; // success
            if (result is string str) Puts("Error while spawning base: {0}", str); // Do not use LogError or LogWarning
        }

Example GetAllEvents API (provided in the next update):

        public void UpdateRaidableBaseTerritories()
        {
            _rbEvents.Clear();
            using var events = Pool.Get<PooledList<(Guid guid, Vector3 pos, float protectionRadius, int level, string baseName, bool allowPVP, ulong ownerId, BasePlayer owner)>>();
            RaidableBases?.Call("GetAllEventsNonAlloc", events);
            if (events.Count == 0)
            {
                return;
            }

            foreach (var evt in events)
            {
                float radius = evt.protectionRadius + 100f;
                _rbEvents.Add((evt.pos, radius * radius, evt.guid));
            }
        }

How to use _rbEvents:

        private List<(Vector3 pos, float radiusSqr, Guid guid)> _rbEvents = new();
        private void OnRaidableBaseStart(Guid guid, Vector3 pos, float protectionRadius)
        {
            float radius = protectionRadius + 100f;
            float radiusSqr = radius * radius;

            for (int i = 0; i < _rbEvents.Count; i++)
            {
                if (_rbEvents[i].guid == guid)
                {
                    _rbEvents[i] = (pos, radiusSqr, guid);
                    return;
                }
            }

            _rbEvents.Add((pos, radiusSqr, guid));
        }

        private void OnRaidableBaseLocationChanged(Guid guid, Vector3 previous, Vector3 current)
        {
            for (int i = 0; i < _rbEvents.Count; i++)
            {
                if (_rbEvents[i].guid == guid)
                {
                    _rbEvents[i] = (current, _rbEvents[i].radiusSqr, guid);
                    return;
                }
            }
        }

        private void OnRaidableBaseEnded(Guid guid, Vector3 pos, float protectionRadius)
        {
            for (int i = _rbEvents.Count - 1; i >= 0; i--)
            {
                if (_rbEvents[i].guid == guid)
                {
                    _rbEvents.RemoveAt(i);
                    return;
                }
            }
        }
        private bool RaidableBaseTerritory(Vector3 position)
        {
            foreach (var (pos, radiusSqr, _) in _rbEvents)
            {
                if ((position - pos).sqrMagnitude <= radiusSqr)
                {
                    return true;
                }
            }
            return false;
        }

 

Edited by nivex
Moose

Posted

Thanks mate, you’re an absolute legend for the quick and detailed response. That gives us exactly what we need to design the controller safely around the supported API and respect the plugin’s boundaries. Really appreciate it!

About Us

Codefling is the largest marketplace for plugins, maps, tools, and more, making it easy for customers to discover new content and for creators to monetize their work.

Downloads
3.2m
Total downloads
Customers
12.3k
Customers served
Files Sold
174.9k
Total sales
Payments
3.8m
Processed total
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.