Files
ReSkate/Extension/Throwdowns/native_flag_spawn.h
T
AyeZeeBB 8444553402 Throwdowns: the throwdown kit, so a mode is a plugin and the SDK knows no particular mode
Plugins register modes (card, replaces, order, flag, players) and publish documents through
reskate.throwdowns.ui: the setup page, the waiting card, HUD slots themed on the game's HUD_<theme>_*
widgets, the match panel, flags and match restrictions. SmokeyDawg58's native plumbing
(throwdown_menu.cpp and its .inl files) renders them and posts throwdown_ui events back. kit::flag
is the one native flag registration. General services added for it: reskate.files, reskate.ui.dialog,
reskate.skater push/hold/bone_cam, reskate.camera.pad_flight, reskate.physics competition,
reskate.session.world, reskate.tricks feed/gesture, and world entities.

His ten modes are now Lua in his plugin: the rules, referee and wire (td/rules, referee, wire), and
every page and HUD document (td/ui*.lua). Extension/Modes and reskate.modes are gone, along with
every race and 1-UP branch in the SDK. The plugin test drives each mode through kit events.

A native setup page is never written to while it closes into flag placement: its rows are not
republished, the stock page is put back once the exit is over, and the stock Players slider is left
alone while a plugin flag is out. This fixes the crashes on the Deathrace button and on 1-UP's
Confirm.
2026-10-20 01:04:54 -05:00

61 lines
3.1 KiB
C++

#pragma once
#include <array>
#include <cmath>
#include <string>
#include <string_view>
// The pose a native flag placement chose, and the assets a plugin mode's flag uses.
namespace dingosdk::multiplayer::native_flag {
using Facing = std::array<float,9>;
inline constexpr Facing default_facing{1,0,0,0,1,0,0,0,1};
inline bool valid_facing(const Facing& facing) {
for(float n:facing)if(!std::isfinite(n) || std::abs(n)>1.01f)return false;
for(unsigned row=0;row<3;++row) {
float length{};for(unsigned i=0;i<3;++i)length+=facing[row*3+i]*facing[row*3+i];
if(std::abs(length-1.f)>.03f)return false;
for(unsigned other=0;other<row;++other) {
float dot{};for(unsigned i=0;i<3;++i)dot+=facing[row*3+i]*facing[other*3+i];
if(std::abs(dot)>.03f)return false;
}
}
const auto determinant=facing[0]*(facing[4]*facing[8]-facing[5]*facing[7])-
facing[1]*(facing[3]*facing[8]-facing[5]*facing[6])+facing[2]*(facing[3]*facing[7]-facing[4]*facing[6]);
return determinant>.97f;
}
inline std::array<float,16> spawn_transform(const std::array<float,3>& position,const Facing& facing) {
return {facing[0],facing[1],facing[2],0,facing[3],facing[4],facing[5],0,
facing[6],facing[7],facing[8],0,position[0],position[1],position[2],1};
}
inline Facing transform_facing(const std::array<float,16>& transform) {
return {transform[0],transform[1],transform[2],transform[4],transform[5],transform[6],transform[8],transform[9],transform[10]};
}
inline float facing_yaw(const Facing& facing) {return std::atan2(facing[6],facing[8])*180.f/3.14159265f;}
inline Facing yaw_facing(float degrees) {
const float radians=degrees*3.14159265f/180.f,co=std::cos(radians),si=std::sin(radians);
return {co,0,-si,0,1,0,si,0,co};
}
// CreateThrowdownQueueParams.SpawnPoint is XYZ plus a yaw in radians.
// TeleportLocation is only a Vec3; treating it as a transform discards the
// facing chosen in the native placement editor and leaves an identity spawn.
inline std::array<float,16> native_spawn_transform(const std::array<float,4>& spawn) {
const float co=std::cos(spawn[3]),si=std::sin(spawn[3]);
return spawn_transform({spawn[0],spawn[1],spawn[2]},Facing{co,0,-si,0,1,0,si,0,co});
}
// A mode's `flag` (custom_modes Mode::flag) is a short name ("duel": InstanceId ReSkate.duel,
// preview World/ReSkate/Throwdowns/Flags/duel_Placement) or the preview prefab's path, whose last
// segment less "_Placement" names the InstanceId. Empty: the stock Spot Battle flag and preview.
struct FlagAssets {
std::string instance, preview; // both empty: stock
};
inline FlagAssets flag_assets(std::string_view flag) {
if(flag.empty())return {};
if(flag.find('/')==std::string_view::npos)
return {"ReSkate."+std::string(flag),"World/ReSkate/Throwdowns/Flags/"+std::string(flag)+"_Placement"};
auto name=flag.substr(flag.rfind('/')+1);
constexpr std::string_view suffix="_Placement";
if(name.size()>suffix.size() && name.ends_with(suffix))name.remove_suffix(suffix.size());
return {name.empty()?std::string{}:"ReSkate."+std::string(name),std::string(flag)};
}
}