ITS BROKEN
This commit is contained in:
@@ -170,10 +170,11 @@ int CollisionSystem::detectCollisions(const AABB& playerAABB, psyqo::Vec3& pushB
|
||||
const FP zero(0);
|
||||
pushBack = psyqo::Vec3{zero, zero, zero};
|
||||
|
||||
// Rebuild spatial grid with all colliders
|
||||
// Rebuild spatial grid with active colliders only
|
||||
m_grid.clear();
|
||||
for (int i = 0; i < m_colliderCount; i++) {
|
||||
if(scene.getGameObject(m_colliders[i].gameObjectIndex)->isActive()) {
|
||||
auto* go = scene.getGameObject(m_colliders[i].gameObjectIndex);
|
||||
if (go && go->isActive()) {
|
||||
m_grid.insert(i, m_colliders[i].bounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ bool CutscenePlayer::play(const char* name, bool loop) {
|
||||
track.initialValues[2] = (int16_t)track.target->position.z.value;
|
||||
}
|
||||
break;
|
||||
case TrackType::ObjectRotationY:
|
||||
// TODO: I added this. Then realized that it only stores rotation matrix. That sucks. To anyone who finds this Pull requests are open :P
|
||||
case TrackType::ObjectRotation:
|
||||
// Initial rotation angles: 0,0,0 (no way to extract Euler from matrix)
|
||||
break;
|
||||
case TrackType::ObjectActive:
|
||||
if (track.target) {
|
||||
@@ -289,7 +289,7 @@ void CutscenePlayer::applyTrack(CutsceneTrack& track) {
|
||||
|
||||
case TrackType::CameraRotation: {
|
||||
if (!m_camera) return;
|
||||
lerpAngles(track.keyframes, track.keyframeCount, track.initialValues, out);
|
||||
lerpKeyframes(track.keyframes, track.keyframeCount, track.initialValues, out);
|
||||
psyqo::Angle rx, ry, rz;
|
||||
rx.value = (int32_t)out[0];
|
||||
ry.value = (int32_t)out[1];
|
||||
@@ -307,13 +307,18 @@ void CutscenePlayer::applyTrack(CutsceneTrack& track) {
|
||||
break;
|
||||
}
|
||||
|
||||
case TrackType::ObjectRotationY: {
|
||||
case TrackType::ObjectRotation: {
|
||||
if (!track.target) return;
|
||||
lerpAngles(track.keyframes, track.keyframeCount, track.initialValues, out);
|
||||
psyqo::Angle yAngle;
|
||||
yAngle.value = (int32_t)out[1];
|
||||
track.target->rotation = psyqo::SoftMath::generateRotationMatrix33(
|
||||
yAngle, psyqo::SoftMath::Axis::Y, m_trig);
|
||||
lerpKeyframes(track.keyframes, track.keyframeCount, track.initialValues, out);
|
||||
psyqo::Angle rx, ry, rz;
|
||||
rx.value = (int32_t)out[0];
|
||||
ry.value = (int32_t)out[1];
|
||||
rz.value = (int32_t)out[2];
|
||||
auto matY = psyqo::SoftMath::generateRotationMatrix33(ry, psyqo::SoftMath::Axis::Y, m_trig);
|
||||
auto matX = psyqo::SoftMath::generateRotationMatrix33(rx, psyqo::SoftMath::Axis::X, m_trig);
|
||||
auto matZ = psyqo::SoftMath::generateRotationMatrix33(rz, psyqo::SoftMath::Axis::Z, m_trig);
|
||||
auto temp = psyqo::SoftMath::multiplyMatrix33(matY, matX);
|
||||
track.target->rotation = psyqo::SoftMath::multiplyMatrix33(temp, matZ);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ enum class TrackType : uint8_t {
|
||||
CameraPosition = 0,
|
||||
CameraRotation = 1,
|
||||
ObjectPosition = 2,
|
||||
ObjectRotationY = 3,
|
||||
ObjectRotation = 3,
|
||||
ObjectActive = 4,
|
||||
UICanvasVisible = 5,
|
||||
UIElementVisible= 6,
|
||||
|
||||
@@ -19,7 +19,7 @@ struct Interactable {
|
||||
uint8_t interactButton;
|
||||
|
||||
// Configuration flags
|
||||
uint8_t flags; // bit 0: isRepeatable, bit 1: showPrompt, bit 2: requireLineOfSight
|
||||
uint8_t flags; // bit 0: isRepeatable, bit 1: showPrompt, bit 2: requireLineOfSight, bit 3: disabled
|
||||
|
||||
// Cooldown between interactions (in frames)
|
||||
uint16_t cooldownFrames;
|
||||
@@ -35,6 +35,11 @@ struct Interactable {
|
||||
bool isRepeatable() const { return flags & 0x01; }
|
||||
bool showPrompt() const { return flags & 0x02; }
|
||||
bool requireLineOfSight() const { return flags & 0x04; }
|
||||
bool isDisabled() const { return flags & 0x08; }
|
||||
void setDisabled(bool disabled) {
|
||||
if (disabled) flags |= 0x08;
|
||||
else flags &= ~0x08;
|
||||
}
|
||||
|
||||
// Check if ready to interact
|
||||
bool canInteract() const {
|
||||
|
||||
87
src/lua.cpp
87
src/lua.cpp
@@ -187,6 +187,12 @@ void psxsplash::Lua::Reset() {
|
||||
}
|
||||
|
||||
void psxsplash::Lua::LoadLuaFile(const char* code, size_t len, int index) {
|
||||
// Store bytecode reference for per-object re-execution in RegisterGameObject.
|
||||
if (index < MAX_LUA_FILES) {
|
||||
m_bytecodeRefs[index] = {code, len};
|
||||
if (index >= m_bytecodeRefCount) m_bytecodeRefCount = index + 1;
|
||||
}
|
||||
|
||||
auto L = m_state;
|
||||
char filename[32];
|
||||
snprintf(filename, sizeof(filename), "lua_asset:%d", index);
|
||||
@@ -289,34 +295,63 @@ void psxsplash::Lua::RegisterGameObject(GameObject* go) {
|
||||
// Initialize event mask for this object
|
||||
uint32_t eventMask = EVENT_NONE;
|
||||
|
||||
if (go->luaFileIndex != -1) {
|
||||
L.rawGetI(LUA_REGISTRYINDEX, m_luascriptsReference);
|
||||
// (1) {} (2) script environments table
|
||||
L.rawGetI(-1, go->luaFileIndex);
|
||||
// (1) {} (2) script environments table (3) script environment table for this object
|
||||
if (go->luaFileIndex != -1 && go->luaFileIndex < m_bytecodeRefCount) {
|
||||
auto& ref = m_bytecodeRefs[go->luaFileIndex];
|
||||
char filename[32];
|
||||
snprintf(filename, sizeof(filename), "lua_asset:%d", go->luaFileIndex);
|
||||
|
||||
// Guard: if the script file failed to load (e.g. compilation error),
|
||||
// the environment will be nil — skip event resolution.
|
||||
if (!L.isTable(-1)) {
|
||||
L.pop(2);
|
||||
if (L.loadBuffer(ref.code, ref.len, filename) == LUA_OK) {
|
||||
// (1) method_table (2) chunk_func
|
||||
|
||||
// Create a per-object environment with __index = _G
|
||||
// so this object's file-level locals are isolated.
|
||||
L.newTable();
|
||||
L.newTable();
|
||||
L.pushGlobalTable();
|
||||
L.setField(-2, "__index");
|
||||
L.setMetatable(-2);
|
||||
// (1) method_table (2) chunk_func (3) env
|
||||
|
||||
// Set env as the chunk's _ENV upvalue
|
||||
L.copy(-1);
|
||||
// (1) method_table (2) chunk_func (3) env (4) env_copy
|
||||
lua_setupvalue(L.getState(), -3, 1);
|
||||
// (1) method_table (2) chunk_func (3) env
|
||||
|
||||
// Move chunk to top for pcall
|
||||
lua_insert(L.getState(), -2);
|
||||
// (1) method_table (2) env (3) chunk_func
|
||||
|
||||
if (L.pcall(0, 0) == LUA_OK) {
|
||||
// (1) method_table (2) env
|
||||
// resolveGlobal expects: (1) method_table, (3) env
|
||||
// Insert a placeholder at position 2 to push env to position 3
|
||||
L.push(); // push nil
|
||||
// (1) method_table (2) env (3) nil
|
||||
lua_insert(L.getState(), 2);
|
||||
// (1) method_table (2) nil (3) env
|
||||
|
||||
// Resolve each event - creates fresh function refs with isolated upvalues
|
||||
if (onCreateMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_CREATE;
|
||||
if (onCollideWithPlayerMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_COLLISION;
|
||||
if (onInteractMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_INTERACT;
|
||||
if (onTriggerEnterMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_TRIGGER_ENTER;
|
||||
if (onTriggerExitMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_TRIGGER_EXIT;
|
||||
if (onUpdateMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_UPDATE;
|
||||
if (onDestroyMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_DESTROY;
|
||||
if (onEnableMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_ENABLE;
|
||||
if (onDisableMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_DISABLE;
|
||||
if (onButtonPressMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_BUTTON_PRESS;
|
||||
if (onButtonReleaseMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_BUTTON_RELEASE;
|
||||
|
||||
L.pop(2); // pop nil and env
|
||||
} else {
|
||||
printf("Lua error: %s\n", L.toString(-1));
|
||||
L.pop(2); // pop error msg and env
|
||||
}
|
||||
} else {
|
||||
|
||||
// Resolve each event and build the bitmask
|
||||
// Only events that exist in the script get their bit set
|
||||
if (onCreateMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_CREATE;
|
||||
if (onCollideWithPlayerMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_COLLISION;
|
||||
if (onInteractMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_INTERACT;
|
||||
if (onTriggerEnterMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_TRIGGER_ENTER;
|
||||
if (onTriggerExitMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_TRIGGER_EXIT;
|
||||
if (onUpdateMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_UPDATE;
|
||||
if (onDestroyMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_DESTROY;
|
||||
if (onEnableMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_ENABLE;
|
||||
if (onDisableMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_DISABLE;
|
||||
if (onButtonPressMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_BUTTON_PRESS;
|
||||
if (onButtonReleaseMethodWrapper.resolveGlobal(L)) eventMask |= EVENT_ON_BUTTON_RELEASE;
|
||||
|
||||
L.pop(2);
|
||||
// (1) {}
|
||||
printf("Lua error: %s\n", L.toString(-1));
|
||||
L.pop(); // pop error msg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
src/lua.h
10
src/lua.h
@@ -180,7 +180,15 @@ class Lua {
|
||||
int m_luascriptsReference = LUA_NOREF;
|
||||
int m_luaSceneScriptsReference = LUA_NOREF;
|
||||
|
||||
// Event mask now stored inline in GameObject::eventMask
|
||||
// Bytecode references for per-object re-execution.
|
||||
// Points into splashpack data which stays in memory for the scene lifetime.
|
||||
static constexpr int MAX_LUA_FILES = 32;
|
||||
struct BytecodeRef {
|
||||
const char* code;
|
||||
size_t len;
|
||||
};
|
||||
BytecodeRef m_bytecodeRefs[MAX_LUA_FILES];
|
||||
int m_bytecodeRefCount = 0;
|
||||
|
||||
template <int methodId, typename methodName>
|
||||
friend struct FunctionWrapper;
|
||||
|
||||
@@ -298,6 +298,19 @@ void LuaAPI::RegisterAll(psyqo::Lua& L, SceneManager* scene, CutscenePlayer* cut
|
||||
|
||||
L.setGlobal("Controls");
|
||||
|
||||
// ========================================================================
|
||||
// INTERACT API
|
||||
// ========================================================================
|
||||
L.newTable();
|
||||
|
||||
L.push(Interact_SetEnabled);
|
||||
L.setField(-2, "SetEnabled");
|
||||
|
||||
L.push(Interact_IsEnabled);
|
||||
L.setField(-2, "IsEnabled");
|
||||
|
||||
L.setGlobal("Interact");
|
||||
|
||||
// ========================================================================
|
||||
// UI API
|
||||
// ========================================================================
|
||||
@@ -1563,6 +1576,49 @@ int LuaAPI::Controls_IsEnabled(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// INTERACT API IMPLEMENTATION
|
||||
// ============================================================================
|
||||
|
||||
int LuaAPI::Interact_SetEnabled(lua_State* L) {
|
||||
psyqo::Lua lua(L);
|
||||
if (!s_sceneManager || !lua.isTable(1) || !lua.isBoolean(2)) return 0;
|
||||
|
||||
lua.getField(1, "__cpp_ptr");
|
||||
auto go = lua.toUserdata<psxsplash::GameObject>(-1);
|
||||
lua.pop();
|
||||
|
||||
if (go && go->hasInteractable()) {
|
||||
auto* inter = s_sceneManager->getInteractable(go->interactableIndex);
|
||||
if (inter) {
|
||||
inter->setDisabled(!lua.toBoolean(2));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LuaAPI::Interact_IsEnabled(lua_State* L) {
|
||||
psyqo::Lua lua(L);
|
||||
if (!s_sceneManager || !lua.isTable(1)) {
|
||||
lua.push(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua.getField(1, "__cpp_ptr");
|
||||
auto go = lua.toUserdata<psxsplash::GameObject>(-1);
|
||||
lua.pop();
|
||||
|
||||
if (go && go->hasInteractable()) {
|
||||
auto* inter = s_sceneManager->getInteractable(go->interactableIndex);
|
||||
if (inter) {
|
||||
lua.push(!inter->isDisabled());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
lua.push(false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// UI API IMPLEMENTATION
|
||||
// ============================================================================
|
||||
|
||||
@@ -277,6 +277,12 @@ private:
|
||||
// Controls.IsEnabled() -> boolean
|
||||
static int Controls_IsEnabled(lua_State* L);
|
||||
|
||||
// Interact.SetEnabled(entity, bool) - enable/disable interaction + prompt for an object
|
||||
static int Interact_SetEnabled(lua_State* L);
|
||||
|
||||
// Interact.IsEnabled(entity) -> boolean
|
||||
static int Interact_IsEnabled(lua_State* L);
|
||||
|
||||
// ========================================================================
|
||||
// UI API - Canvas and element control
|
||||
// ========================================================================
|
||||
|
||||
@@ -314,8 +314,14 @@ void psxsplash::SceneManager::GameTick(psyqo::GPU &gpu) {
|
||||
psyqo::FixedPoint<12> py = static_cast<psyqo::FixedPoint<12>>(m_playerPosition.y);
|
||||
psyqo::FixedPoint<12> pz = static_cast<psyqo::FixedPoint<12>>(m_playerPosition.z);
|
||||
psyqo::FixedPoint<12> h = static_cast<psyqo::FixedPoint<12>>(m_playerHeight);
|
||||
playerAABB.min = psyqo::Vec3{px - r, py - h, pz - r};
|
||||
playerAABB.max = psyqo::Vec3{px + r, py, pz + r};
|
||||
// Y is inverted on PS1: negative = up, positive = down.
|
||||
// m_playerPosition.y is the camera (head), feet are at py + h.
|
||||
// Leave a small gap at the bottom so the floor geometry doesn't
|
||||
// trigger constant collisions (floor contact is handled by nav).
|
||||
psyqo::FixedPoint<12> bodyBottom;
|
||||
bodyBottom.value = h.value * 3 / 4; // 75% of height below camera
|
||||
playerAABB.min = psyqo::Vec3{px - r, py, pz - r};
|
||||
playerAABB.max = psyqo::Vec3{px + r, py + bodyBottom, pz + r};
|
||||
}
|
||||
|
||||
psyqo::Vec3 pushBack;
|
||||
@@ -519,6 +525,7 @@ void psxsplash::SceneManager::updateInteractionSystem() {
|
||||
|
||||
for (auto* interactable : m_interactables) {
|
||||
if (!interactable) continue;
|
||||
if (interactable->isDisabled()) continue;
|
||||
|
||||
auto* go = getGameObject(interactable->gameObjectIndex);
|
||||
if (!go || !go->isActive()) continue;
|
||||
|
||||
@@ -86,6 +86,12 @@ class SceneManager {
|
||||
void setControlsEnabled(bool enabled) { m_controlsEnabled = enabled; }
|
||||
bool isControlsEnabled() const { return m_controlsEnabled; }
|
||||
|
||||
// Interactable access (for Lua API)
|
||||
Interactable* getInteractable(uint16_t index) {
|
||||
if (index < m_interactables.size()) return m_interactables[index];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Scene loading (for multi-scene support)
|
||||
void requestSceneLoad(int sceneIndex);
|
||||
int getCurrentSceneIndex() const { return m_currentSceneIndex; }
|
||||
|
||||
Reference in New Issue
Block a user