Fixed bug with state allocation and other small stuff.

This commit is contained in:
Kapendev 2025-03-12 16:02:28 +02:00
parent 62a6d18673
commit fe4b4157d2
4 changed files with 68 additions and 65 deletions

View file

@ -21,8 +21,9 @@ public import joka.types;
EngineState* engineState;
enum defaultEngineTexturesCapacity = 256;
enum defaultEngineSoundsCapacity = 128;
enum defaultEngineFontsCapacity = 64;
enum defaultEngineResourcesCapacity = 256;
/// A type representing flipping orientations.
enum Flip : ubyte {
@ -1266,15 +1267,11 @@ void openUrl(IStr url = "https://github.com/Kapendev/parin") {
/// Opens a window with the specified size and title.
/// You should avoid calling this function manually.
// NOTE: This function frees memory and we skip some stuff in release builds since the OS will free the memory for us.
@trusted
void openWindow(int width, int height, const(IStr)[] args, IStr title = "Parin") {
if (rl.IsWindowReady) return;
engineState = cast(EngineState*) stdc.malloc(EngineState.sizeof);
stdc.memset(engineState, 0, EngineState.sizeof);
// This part is a hack for the `runGame` mixin.
engineState.envArgsBuffer.clear();
foreach (arg; args) engineState.envArgsBuffer.append(arg);
// Raylib stuff.
rl.SetConfigFlags(rl.FLAG_WINDOW_RESIZABLE | rl.FLAG_VSYNC_HINT);
rl.SetTraceLogLevel(rl.LOG_ERROR);
@ -1285,14 +1282,15 @@ void openWindow(int width, int height, const(IStr)[] args, IStr title = "Parin")
rl.rlSetBlendFactorsSeparate(0x0302, 0x0303, 1, 0x0303, 0x8006, 0x8006);
setWindowMinSize(240, 135);
// Engine stuff.
foreach (arg; args) engineState.envArgsBuffer.append(arg);
engineState.flags.canUseAssetsPath = true;
engineState.fullscreenState.previousWindowWidth = width;
engineState.fullscreenState.previousWindowHeight = height;
engineState.borderColor = black;
// Ready resources.
engineState.droppedFilePathsBuffer.reserve(defaultEngineResourcesCapacity);
engineState.textures.reserve(defaultEngineResourcesCapacity);
engineState.sounds.reserve(defaultEngineResourcesCapacity);
engineState.droppedFilePathsBuffer.reserve(defaultEngineFontsCapacity);
engineState.textures.reserve(defaultEngineTexturesCapacity);
engineState.sounds.reserve(defaultEngineSoundsCapacity);
engineState.fonts.reserve(defaultEngineFontsCapacity);
engineState.viewport.color = gray;
engineState.loadTextBuffer.reserve(8192);
@ -1303,9 +1301,7 @@ void openWindow(int width, int height, const(IStr)[] args, IStr title = "Parin")
auto monogramImage = rl.LoadImageFromMemory(".png", monogramData.ptr, cast(int) monogramData.length);
auto monogramTexture = rl.LoadTextureFromImage(monogramImage);
engineState.debugFont = monogramTexture.toParin().toFont(6, 12);
debug {
rl.UnloadImage(monogramImage);
}
rl.UnloadImage(monogramImage);
}
/// Updates the window every frame with the given function.
@ -1417,23 +1413,19 @@ void updateWindow(bool function(float dt) updateFunc) {
/// Closes the window.
/// You should avoid calling this function manually.
// NOTE: This function frees memory and we skip some stuff in release builds since the OS will free the memory for us.
@trusted
void closeWindow() {
if (!rl.IsWindowReady()) return;
debug {
freeResources();
engineState.viewport.free();
engineState.debugFont.free();
engineState.envArgsBuffer.free();
engineState.droppedFilePathsBuffer.free();
engineState.loadTextBuffer.free();
engineState.saveTextBuffer.free();
engineState.assetsPath.free();
stdc.free(engineState);
engineState = null;
}
// This is outside because who knows, maybe raylib needs that.
freeResources();
engineState.viewport.free();
engineState.debugFont.free();
engineState.envArgsBuffer.free();
engineState.droppedFilePathsBuffer.free();
engineState.loadTextBuffer.free();
engineState.saveTextBuffer.free();
engineState.assetsPath.free();
stdc.free(engineState);
engineState = null;
rl.CloseAudioDevice();
rl.CloseWindow();
}
@ -2430,8 +2422,8 @@ mixin template runGame(alias readyFunc, alias updateFunc, alias finishFunc, int
version (D_BetterC) {
extern(C)
void main(int argc, immutable(char)** argv) {
openWindow(width, height, [], title);
foreach (i; 0 .. argc) engineState.envArgsBuffer.append(argv[i].toStr());
openWindow(width, height, engineState.envArgsBuffer[], title);
readyFunc();
updateWindow(&updateFunc);
finishFunc();

View file

@ -125,16 +125,12 @@ struct WallBoxProperties {
Vec2 remainder;
OneWaySide oneWaySide;
WallBoxFlags flags;
byte gridX;
byte gridY;
}
struct ActorBoxProperties {
Vec2 remainder;
RideSide rideSide;
ActorBoxFlags flags;
byte gridX;
byte gridY;
}
struct BoxWorld {
@ -158,20 +154,22 @@ struct BoxWorld {
group.length = 0;
}
foreach (i, ref properties; wallsProperties) {
properties.gridX = walls[i].position.x / gridTileWidth - (walls[i].position.x < 0);
properties.gridY = walls[i].position.y / gridTileHeight - (walls[i].position.y < 0);
// TODO: There are two problems to think about. Negative values and boxes touching more than one group.
auto id = cast(TaggedBaseBoxId) (i + 1);
id &= ~(1 << 31);
grid[properties.gridY, properties.gridX].append(id);
auto id = cast(BaseBoxId) (i + 1);
auto tagged = id & ~(1 << 31);
auto positions = getWallGridPositions(id);
grid[positions[0].y, positions[0].x].append(tagged);
if (positions[0] != positions[1]) {
grid[positions[1].y, positions[1].x].append(tagged);
}
}
foreach (i, ref properties; actorsProperties) {
properties.gridX = actors[i].position.x / gridTileWidth - (actors[i].position.x < 0);
properties.gridY = actors[i].position.y / gridTileHeight - (actors[i].position.y < 0);
// TODO: There are two problems to think about. Negative values and boxes touching more than one group.
auto id = cast(TaggedBaseBoxId) (i + 1);
id |= (1 << 31);
grid[properties.gridY, properties.gridX].append(id);
auto id = cast(BaseBoxId) (i + 1);
auto tagged = id | (1 << 31);
auto positions = getWallGridPositions(id);
grid[positions[0].y, positions[0].x].append(tagged);
if (positions[0] != positions[1]) {
grid[positions[1].y, positions[1].x].append(tagged);
}
}
}
@ -190,15 +188,6 @@ struct BoxWorld {
return walls[id - 1];
}
ref IRect getActor(ActorBoxId id) {
if (id == 0) {
assert(0, "ID `0` is always invalid and represents a box that was never created.");
} else if (id > actors.length) {
assert(0, "ID `{}` does not exist.".format(id));
}
return actors[id - 1];
}
ref WallBoxProperties getWallProperties(WallBoxId id) {
if (id == 0) {
assert(0, "ID `0` is always invalid and represents a box that was never created.");
@ -208,6 +197,26 @@ struct BoxWorld {
return wallsProperties[id - 1];
}
@trusted
IVec2[2] getWallGridPositions(WallBoxId id) {
IVec2[2] result = void;
auto i = id - 1;
result[0].x = walls[i].position.x / gridTileWidth - (walls[i].position.x < 0);
result[0].y = walls[i].position.y / gridTileHeight - (walls[i].position.y < 0);
result[1].x = (walls[i].position.x + walls[i].size.x) - ((walls[i].position.x + walls[i].size.x) < 0);
result[1].y = (walls[i].position.y + walls[i].size.y) - ((walls[i].position.y + walls[i].size.y) < 0);
return result;
}
ref IRect getActor(ActorBoxId id) {
if (id == 0) {
assert(0, "ID `0` is always invalid and represents a box that was never created.");
} else if (id > actors.length) {
assert(0, "ID `{}` does not exist.".format(id));
}
return actors[id - 1];
}
ref ActorBoxProperties getActorProperties(ActorBoxId id) {
if (id == 0) {
assert(0, "ID `0` is always invalid and represents a box that was never created.");
@ -217,14 +226,21 @@ struct BoxWorld {
return actorsProperties[id - 1];
}
@trusted
IVec2[2] getActorGridPositions(WallBoxId id) {
IVec2[2] result = void;
auto i = id - 1;
result[0].x = actors[i].position.x / gridTileWidth - (actors[i].position.x < 0);
result[0].y = actors[i].position.y / gridTileHeight - (actors[i].position.y < 0);
result[1].x = (actors[i].position.x + actors[i].size.x) - ((actors[i].position.x + actors[i].size.x) < 0);
result[1].y = (actors[i].position.y + actors[i].size.y) - ((actors[i].position.y + actors[i].size.y) < 0);
return result;
}
WallBoxId appendWall(IRect box, OneWaySide oneWaySide = OneWaySide.none) {
walls.append(box);
wallsProperties.append(WallBoxProperties());
wallsProperties[$ - 1].oneWaySide = oneWaySide;
if (gridTileWidth != 0 || gridTileHeight != 0) {
wallsProperties[$ - 1].gridX = box.position.x / gridTileWidth - (box.position.x < 0);
wallsProperties[$ - 1].gridY = box.position.y / gridTileHeight - (box.position.y < 0);
}
return cast(BaseBoxId) walls.length;
}
@ -232,10 +248,6 @@ struct BoxWorld {
actors.append(box);
actorsProperties.append(ActorBoxProperties());
actorsProperties[$ - 1].rideSide = rideSide;
if (gridTileWidth != 0 || gridTileHeight != 0) {
actorsProperties[$ - 1].gridX = box.position.x / gridTileWidth - (box.position.x < 0);
actorsProperties[$ - 1].gridY = box.position.y / gridTileHeight - (box.position.y < 0);
}
return cast(BaseBoxId) actors.length;
}
@ -306,7 +318,6 @@ struct BoxWorld {
} else {
actor.position.x += moveSign;
move -= moveSign;
properties.gridX = actor.position.x / gridTileWidth - (actor.position.x < 0);
}
}
return 0;
@ -361,7 +372,6 @@ struct BoxWorld {
} else {
actor.position.y += moveSign;
move -= moveSign;
properties.gridY = actor.position.y / gridTileHeight - (actor.position.y < 0);
}
}
return 0;
@ -460,7 +470,6 @@ struct BoxWorld {
if (move.x != 0) {
wall.position.x += move.x;
properties.remainder.x -= move.x;
properties.gridX = wall.position.x / gridTileWidth - (wall.position.x < 0);
if (~properties.flags & boxPassableFlag) {
properties.flags |= boxPassableFlag;
foreach (i, ref actor; actors) {
@ -487,7 +496,6 @@ struct BoxWorld {
if (move.y != 0) {
wall.position.y += move.y;
properties.remainder.y -= move.y;
properties.gridY = wall.position.y / gridTileHeight - (wall.position.y < 0);
if (~properties.flags & boxPassableFlag) {
properties.flags |= boxPassableFlag;
foreach (i, ref actor; actors) {

View file

@ -317,7 +317,10 @@ struct Story {
}
if (token.isMaybeStoryOp) {
auto tempOp = token.toStoryOp();
if (tempOp.isNone) return tempOp.fault;
if (tempOp.isNone) {
faultTokenPosition = tokenCount;
return tempOp.fault;
}
auto op = tempOp.value;
final switch (op) {
case ADD:

View file

@ -111,7 +111,7 @@ int findSpaceInTextField(IStr text) {
@trusted
void prepareUi() {
if (uiState == null) {
// NOTE: This will leak, but who cares.
// NOTE: This leaks. THIS IS SO BAD WHERE IS `Box::leak` IN THIS CODEBASE???
uiState = cast(UiState*) stdc.malloc(UiState.sizeof);
uiPreviousState = cast(UiState*) stdc.malloc(UiState.sizeof);
stdc.memset(uiState, 0, UiState.sizeof);