Cubyz/src/gui/windows/save_creation.zig
Krzysztof Wiśniewski 67135b433d
Add chat history accessible with up/down arrows (#1244)
* Add up down message history

* Deduplicate messages when inserting into history

* Add dedicated function for inserting strings into TextInput

* Fix formatting issues

* Change history behavior

* Rename inputString to setString

* Move clearing to setString

* Apply suggestions from code review

Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>

* Remove unused cursor capture

* Use FixedSizeCircularBuffer for history

* Restore large queue size

* Allow navigation to empty entry

* self.len must never be bigger than capacity

* Move optional callbacks into struct

* Use enum for moveCursorVertically return value

* WA attempt #1

* Fix edge case from review

* Update src/gui/windows/chat.zig

Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>

* Remove isEmpty and isFull

* Allow for empty history entry

* Change empty message handling some more

* Remove unused methods

* Go to hell with all of those edge cases <3

* WA for 4b

* Remove CircularBufferQueue methods

* Fix queue thing

---------

Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>
2025-05-04 12:57:25 +02:00

133 lines
4.9 KiB
Zig

const std = @import("std");
const main = @import("main");
const ConnectionManager = main.network.ConnectionManager;
const settings = main.settings;
const Vec2f = main.vec.Vec2f;
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const GuiWindow = gui.GuiWindow;
const Button = @import("../components/Button.zig");
const HorizontalList = @import("../components/HorizontalList.zig");
const Label = @import("../components/Label.zig");
const TextInput = @import("../components/TextInput.zig");
const CheckBox = @import("../components/CheckBox.zig");
const VerticalList = @import("../components/VerticalList.zig");
pub var window = GuiWindow{
.contentSize = Vec2f{128, 256},
};
const padding: f32 = 8;
var textInput: *TextInput = undefined;
var gamemode: main.game.Gamemode = .creative;
var gamemodeInput: *Button = undefined;
var allowCheats: bool = true;
fn gamemodeCallback(_: usize) void {
gamemode = std.meta.intToEnum(main.game.Gamemode, @intFromEnum(gamemode) + 1) catch @enumFromInt(0);
gamemodeInput.child.label.updateText(@tagName(gamemode));
}
fn allowCheatsCallback(allow: bool) void {
allowCheats = allow;
}
fn createWorld(_: usize) void {
flawedCreateWorld() catch |err| {
std.log.err("Error while creating new world: {s}", .{@errorName(err)});
};
}
fn flawedCreateWorld() !void {
const worldName = textInput.currentString.items;
const saveFolder = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}", .{worldName}) catch unreachable;
defer main.stackAllocator.free(saveFolder);
if(std.fs.cwd().openDir(saveFolder, .{})) |_dir| {
var dir = _dir;
dir.close();
return error.AlreadyExists;
} else |_| {}
try main.files.makeDir(saveFolder);
{
const generatorSettingsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/generatorSettings.zig.zon", .{worldName}) catch unreachable;
defer main.stackAllocator.free(generatorSettingsPath);
const generatorSettings = main.ZonElement.initObject(main.stackAllocator);
defer generatorSettings.deinit(main.stackAllocator);
const climateGenerator = main.ZonElement.initObject(main.stackAllocator);
climateGenerator.put("id", "cubyz:noise_based_voronoi"); // TODO: Make this configurable
generatorSettings.put("climateGenerator", climateGenerator);
const mapGenerator = main.ZonElement.initObject(main.stackAllocator);
mapGenerator.put("id", "cubyz:mapgen_v1"); // TODO: Make this configurable
generatorSettings.put("mapGenerator", mapGenerator);
const climateWavelengths = main.ZonElement.initObject(main.stackAllocator);
climateWavelengths.put("hot_cold", 2400);
climateWavelengths.put("land_ocean", 3200);
climateWavelengths.put("wet_dry", 1800);
climateWavelengths.put("vegetation", 1600);
climateWavelengths.put("mountain", 512);
generatorSettings.put("climateWavelengths", climateWavelengths);
try main.files.writeZon(generatorSettingsPath, generatorSettings);
}
{
const gamerulePath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/gamerules.zig.zon", .{worldName}) catch unreachable;
defer main.stackAllocator.free(gamerulePath);
const gamerules = main.ZonElement.initObject(main.stackAllocator);
defer gamerules.deinit(main.stackAllocator);
gamerules.put("default_gamemode", @tagName(gamemode));
gamerules.put("cheats", allowCheats);
try main.files.writeZon(gamerulePath, gamerules);
}
{ // Make assets subfolder
const assetsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/assets", .{worldName}) catch unreachable;
defer main.stackAllocator.free(assetsPath);
try main.files.makeDir(assetsPath);
}
// TODO: Make the seed configurable
gui.closeWindowFromRef(&window);
gui.windowlist.save_selection.needsUpdate = true;
gui.openWindow("save_selection");
}
pub fn onOpen() void {
const list = VerticalList.init(.{padding, 16 + padding}, 300, 8);
var num: usize = 1;
while(true) {
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/Save{}", .{num}) catch unreachable;
defer main.stackAllocator.free(path);
var dir = std.fs.cwd().openDir(path, .{}) catch break;
dir.close();
num += 1;
}
const name = std.fmt.allocPrint(main.stackAllocator.allocator, "Save{}", .{num}) catch unreachable;
defer main.stackAllocator.free(name);
textInput = TextInput.init(.{0, 0}, 128, 22, name, .{.callback = &createWorld}, .{});
list.add(textInput);
gamemodeInput = Button.initText(.{0, 0}, 128, @tagName(gamemode), .{.callback = &gamemodeCallback});
list.add(gamemodeInput);
list.add(CheckBox.init(.{0, 0}, 128, "Allow Cheats", true, &allowCheatsCallback));
list.add(Button.initText(.{0, 0}, 128, "Create World", .{.callback = &createWorld}));
list.finish(.center);
window.rootComponent = list.toComponent();
window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding));
gui.updateWindowPositions();
}
pub fn onClose() void {
if(window.rootComponent) |*comp| {
comp.deinit();
}
}