refactor: reorganize pxl8 into client/src/ module structure
- core/: main entry, types, logging, I/O, RNG - asset/: ase loader, cart, save, embed - gfx/: graphics, animation, atlas, fonts, tilemap, transitions - sfx/: audio - script/: lua/fennel runtime, REPL - hal/: platform abstraction (SDL3) - world/: BSP, world, procedural gen - math/: math utilities - game/: GUI, replay - lua/: Lua API modules
This commit is contained in:
parent
272e0bc615
commit
49256db1bd
107 changed files with 6678 additions and 3715 deletions
600
resilient-sparking-wirth.md
Normal file
600
resilient-sparking-wirth.md
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
# Prydain Architecture Restructuring Plan
|
||||
|
||||
## Vision: pxl8 as Console, Games as Mods
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ prydain/ (a mod - game content) │
|
||||
│ ├── cart.fnl # Manifest │
|
||||
│ ├── main.fnl # Entry point │
|
||||
│ ├── mod/ # Game modules (Fennel) │
|
||||
│ └── res/ # Resources (models, textures, sounds) │
|
||||
└────────────────────────┬────────────────────────────────────┘
|
||||
│ runs on
|
||||
┌────────────────────────┴────────────────────────────────────┐
|
||||
│ pxl8 (the console/platform) │
|
||||
│ ├── client/ # C client (gfx, sfx, hal, script) │
|
||||
│ │ └── src/ # C source files │
|
||||
│ ├── server/ # Rust bevy_ecs game server │
|
||||
│ │ └── src/ # Rust source files │
|
||||
│ └── demo/ # Example mod │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Client/Server Split (Quake-style):**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Fennel mod/ (runs on CLIENT via pxl8/LuaJIT) │
|
||||
│ Game logic, behaviors, content definitions │
|
||||
│ Sends commands to server, receives snapshots │
|
||||
└────────────────────────┬────────────────────────────────────┘
|
||||
│ LuaJIT FFI
|
||||
┌────────────────────────┴────────────────────────────────────┐
|
||||
│ C pxl8 client - rendering, audio, input, networking │
|
||||
└────────────────────────┬────────────────────────────────────┘
|
||||
│ protocol (commands ↑, snapshots ↓)
|
||||
┌────────────────────────┴────────────────────────────────────┐
|
||||
│ Rust bevy_ecs server - authoritative simulation │
|
||||
│ (ships with pxl8, games extend via Fennel + optional Rust) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Key Architectural Properties
|
||||
|
||||
- **pxl8 is the console**: Ships C client + Rust server
|
||||
- **Mods are games**: cart.fnl + mod/*.fnl + res/*
|
||||
- **prydain is just a mod**: Game content, not engine code
|
||||
- **Server ships with pxl8**: Generic bevy_ecs, extended by mods
|
||||
- **Simple mods**: Just Fennel, no server needed (client-only)
|
||||
- **Complex mods**: Use server for authoritative simulation
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Reorganize C pxl8 into Modules
|
||||
|
||||
**Goal**: Clean up pxl8's flat structure into logical modules.
|
||||
|
||||
### New Directory Structure
|
||||
|
||||
```
|
||||
~/code/pxl8/
|
||||
client/ # C client
|
||||
src/
|
||||
core/
|
||||
pxl8.c # Main entry, lifecycle
|
||||
pxl8_types.h # Core types
|
||||
pxl8_log.c/h # Logging
|
||||
pxl8_io.c/h # File I/O
|
||||
math/
|
||||
pxl8_math.c/h # Vec3, Mat4, etc.
|
||||
pxl8_simd.h # SIMD abstractions
|
||||
gfx/
|
||||
pxl8_gfx.c/h # Graphics frontend (backend dispatch)
|
||||
pxl8_cpu.c # CPU backend (prydain optimizations)
|
||||
pxl8_gpu.c # GPU backend (SDL3_GPU, future)
|
||||
pxl8_colormap.c/h # 64×256 lighting LUT
|
||||
pxl8_dither.c/h # Bayer dithering
|
||||
pxl8_atlas.c/h # Texture atlas
|
||||
pxl8_vfx.c/h # Particle effects
|
||||
sfx/
|
||||
pxl8_sfx.c/h # Audio synthesis
|
||||
script/
|
||||
pxl8_script.c/h # Lua/Fennel runtime
|
||||
pxl8_repl.c/h # REPL
|
||||
hal/
|
||||
pxl8_hal.h # Platform abstraction interface
|
||||
pxl8_sdl3.c/h # SDL3 implementation
|
||||
world/
|
||||
pxl8_bsp.c/h # BSP loading/rendering
|
||||
pxl8_world.c/h # World management
|
||||
net/ # NEW
|
||||
pxl8_protocol.h # Message definitions
|
||||
pxl8_net.c/h # Networking (client side)
|
||||
lua/ # Existing Lua API
|
||||
pxl8.lua
|
||||
pxl8/*.lua
|
||||
include/
|
||||
pxl8.h # Public API header
|
||||
pxl8.sh # Build script (bash)
|
||||
server/ # Rust bevy_ecs server
|
||||
Cargo.toml
|
||||
src/
|
||||
lib.rs
|
||||
...
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
- All existing pxl8 demos still compile and run
|
||||
- No functionality regression
|
||||
- Build system finds all sources in new locations
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Enhance pxl8_gfx with Prydain Optimizations
|
||||
|
||||
**Goal**: Port prydain's rendering optimizations into pxl8_gfx, with backend abstraction for future GPU support.
|
||||
|
||||
### Backend Architecture
|
||||
|
||||
```
|
||||
pxl8_gfx.c/h # Frontend API (existing, enhanced)
|
||||
│
|
||||
├── pxl8_cpu.c # CPU/software backend (prydain techniques)
|
||||
│
|
||||
└── pxl8_gpu.c # GPU backend (SDL3_GPU, future)
|
||||
```
|
||||
|
||||
### Files to Create/Modify
|
||||
|
||||
```
|
||||
pxl8/client/src/gfx/
|
||||
pxl8_gfx.c/h # EXISTING - add backend dispatch
|
||||
pxl8_cpu.c # NEW - CPU rasterizer (prydain optimizations)
|
||||
pxl8_gpu.c # FUTURE - SDL3_GPU backend
|
||||
pxl8_colormap.c/h # NEW - 64×256 lighting LUT
|
||||
pxl8_dither.c/h # NEW - Bayer dithering
|
||||
|
||||
pxl8/client/src/math/
|
||||
pxl8_simd.h # SSE2/NEON/scalar abstractions
|
||||
```
|
||||
|
||||
### Key Functions to Port
|
||||
|
||||
From `prydain/src/gfx/backend/cpu/renderer.rs`:
|
||||
|
||||
| Function | Lines | Target |
|
||||
|----------|-------|--------|
|
||||
| `rasterize_triangle_opaque_fast` | 1184-1466 | `pxl8_raster.c` |
|
||||
| `rasterize_span_simd_x4` | 1063-1180 | `pxl8_raster.c` |
|
||||
| `render_glows` | 689-971 | `pxl8_vfx.c` |
|
||||
| `clip_triangle_near` | 132-186 | `pxl8_raster.c` |
|
||||
|
||||
From `prydain/src/gfx/backend/cpu/shader.rs`:
|
||||
|
||||
| Function | Lines | Target |
|
||||
|----------|-------|--------|
|
||||
| `calc_light` | 113-163 | `pxl8_lighting.c` |
|
||||
| `fast_inv_sqrt` | 181-205 | `pxl8_math.c` |
|
||||
|
||||
From `prydain/src/gfx/color/map.rs`:
|
||||
|
||||
| Function | Target |
|
||||
|----------|--------|
|
||||
| ColorMap LUT generation | `pxl8_colormap.c` |
|
||||
| `lookup()` | `pxl8_colormap.c` |
|
||||
|
||||
### C Rasterizer API
|
||||
|
||||
```c
|
||||
// pxl8_raster.h
|
||||
typedef struct pxl8_rasterizer pxl8_rasterizer;
|
||||
|
||||
pxl8_rasterizer* pxl8_rasterizer_create(u32 width, u32 height);
|
||||
void pxl8_rasterizer_destroy(pxl8_rasterizer* r);
|
||||
|
||||
void pxl8_rasterizer_set_frame(pxl8_rasterizer* r, const pxl8_frame* frame);
|
||||
void pxl8_rasterizer_clear(pxl8_rasterizer* r, u8 color);
|
||||
void pxl8_rasterizer_clear_depth(pxl8_rasterizer* r);
|
||||
|
||||
void pxl8_rasterizer_draw_triangles(
|
||||
pxl8_rasterizer* r,
|
||||
const pxl8_vertex* verts,
|
||||
u32 vert_count,
|
||||
const u16* indices,
|
||||
u32 index_count,
|
||||
const pxl8_material* material
|
||||
);
|
||||
|
||||
void pxl8_rasterizer_draw_glows(
|
||||
pxl8_rasterizer* r,
|
||||
const pxl8_glow* glows,
|
||||
u32 count
|
||||
);
|
||||
|
||||
u8* pxl8_rasterizer_framebuffer(pxl8_rasterizer* r);
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
- Render same scene in Rust and C, pixel-diff comparison
|
||||
- Benchmark: C ≥ Rust performance
|
||||
- Test all render paths (opaque, alpha, passthrough)
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Define Client/Server Protocol
|
||||
|
||||
**Goal**: Language-agnostic message format for client↔server communication.
|
||||
|
||||
### Protocol Header
|
||||
|
||||
```c
|
||||
// pxl8/src/net/pxl8_protocol.h
|
||||
|
||||
// Message types
|
||||
typedef enum {
|
||||
PXL8_MSG_INPUT = 1, // Client → Server
|
||||
PXL8_MSG_COMMAND = 2, // Client → Server (from Fennel scripts)
|
||||
PXL8_MSG_SNAPSHOT = 3, // Server → Client
|
||||
PXL8_MSG_EVENT = 4, // Server → Client (sounds, particles)
|
||||
} pxl8_msg_type;
|
||||
|
||||
// Client → Server: Input
|
||||
typedef struct {
|
||||
u64 tick;
|
||||
u64 timestamp;
|
||||
f32 move_x, move_y; // Movement input
|
||||
f32 look_dx, look_dy; // Mouse delta
|
||||
u32 buttons; // Bitfield: attack, use, jump, etc.
|
||||
} pxl8_input_msg;
|
||||
|
||||
// Client → Server: Script command
|
||||
typedef struct {
|
||||
u64 tick;
|
||||
u16 cmd_type; // Command enum
|
||||
u8 payload[64]; // Command-specific data
|
||||
} pxl8_command_msg;
|
||||
|
||||
// Server → Client: Entity state
|
||||
typedef struct {
|
||||
u64 entity_id;
|
||||
u16 archetype;
|
||||
f32 x, y, z;
|
||||
f32 yaw;
|
||||
u16 anim_id;
|
||||
f32 anim_time;
|
||||
u32 flags;
|
||||
} pxl8_entity_state;
|
||||
|
||||
// Server → Client: World snapshot
|
||||
typedef struct {
|
||||
u64 tick;
|
||||
f32 time;
|
||||
u16 entity_count;
|
||||
pxl8_entity_state entities[]; // Flexible array
|
||||
} pxl8_snapshot_msg;
|
||||
|
||||
// Server → Client: Events
|
||||
typedef struct {
|
||||
u8 event_type; // Sound, particle, damage flash, etc.
|
||||
u8 payload[15]; // Event-specific data
|
||||
} pxl8_event_msg;
|
||||
```
|
||||
|
||||
### Serialization
|
||||
|
||||
Simple binary format, network byte order:
|
||||
```c
|
||||
// pxl8_protocol.c
|
||||
size_t pxl8_serialize_input(const pxl8_input_msg* msg, u8* buf, size_t len);
|
||||
size_t pxl8_deserialize_input(const u8* buf, size_t len, pxl8_input_msg* msg);
|
||||
size_t pxl8_serialize_snapshot(const pxl8_snapshot_msg* msg, u8* buf, size_t len);
|
||||
size_t pxl8_deserialize_snapshot(const u8* buf, size_t len, pxl8_snapshot_msg* msg);
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
- Round-trip serialization test
|
||||
- Cross-language test (C client, Rust server)
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Client Implementation
|
||||
|
||||
**Goal**: pxl8 client that connects to server, renders snapshots.
|
||||
|
||||
### Client State
|
||||
|
||||
```c
|
||||
// pxl8/src/net/pxl8_client.h
|
||||
typedef struct pxl8_client pxl8_client;
|
||||
|
||||
pxl8_client* pxl8_client_create(void);
|
||||
void pxl8_client_destroy(pxl8_client* c);
|
||||
|
||||
// Connection
|
||||
bool pxl8_client_connect(pxl8_client* c, const char* address, u16 port);
|
||||
void pxl8_client_disconnect(pxl8_client* c);
|
||||
|
||||
// Input
|
||||
void pxl8_client_send_input(pxl8_client* c, const pxl8_input_msg* input);
|
||||
void pxl8_client_send_command(pxl8_client* c, const pxl8_command_msg* cmd);
|
||||
|
||||
// Receive
|
||||
bool pxl8_client_poll(pxl8_client* c); // Process incoming messages
|
||||
pxl8_snapshot_msg* pxl8_client_latest_snapshot(pxl8_client* c);
|
||||
|
||||
// Interpolation
|
||||
f32 pxl8_client_interp_time(pxl8_client* c);
|
||||
void pxl8_client_get_entity_transform(
|
||||
pxl8_client* c,
|
||||
u64 entity_id,
|
||||
pxl8_vec3* pos,
|
||||
f32* yaw
|
||||
);
|
||||
```
|
||||
|
||||
### Client Loop
|
||||
|
||||
```c
|
||||
void game_loop(pxl8_client* client, pxl8_rasterizer* raster) {
|
||||
while (running) {
|
||||
f32 dt = get_delta_time();
|
||||
|
||||
// Poll input
|
||||
pxl8_input_state input = pxl8_hal_poll_input();
|
||||
|
||||
// Send to server
|
||||
pxl8_input_msg msg = make_input_msg(&input);
|
||||
pxl8_client_send_input(client, &msg);
|
||||
|
||||
// Receive snapshots
|
||||
pxl8_client_poll(client);
|
||||
|
||||
// Render interpolated state
|
||||
pxl8_snapshot_msg* snap = pxl8_client_latest_snapshot(client);
|
||||
render_world(raster, client, snap);
|
||||
|
||||
// Present
|
||||
pxl8_hal_present();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
- Client connects to local server
|
||||
- Entities render at interpolated positions
|
||||
- Input reaches server, affects simulation
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Rust Server (ships with pxl8)
|
||||
|
||||
**Goal**: Generic bevy_ecs server that mods can extend.
|
||||
|
||||
### Crate Structure (inside pxl8)
|
||||
|
||||
```
|
||||
pxl8/
|
||||
server/ # Rust bevy_ecs game server
|
||||
Cargo.toml
|
||||
src/
|
||||
lib.rs
|
||||
server.rs # Main server loop
|
||||
protocol.rs # Protocol types (shared with C)
|
||||
systems/
|
||||
physics.rs # Generic physics
|
||||
visibility.rs # PVS, line of sight
|
||||
components.rs # Generic components (Position, Velocity, etc.)
|
||||
```
|
||||
|
||||
**Minimal dependencies:**
|
||||
- `bevy_ecs` only (not full Bevy)
|
||||
- `no_std` compatible where possible
|
||||
- No rendering, audio, or platform code (that's C pxl8's job)
|
||||
|
||||
Server is **generic** - mods extend it via Fennel scripts defining behaviors.
|
||||
|
||||
**If Fennel is too slow** (e.g., pathfinding for 100+ mobs), improve the generic server—that benefits all mods. No plugin system for now; can add later if there's demand from a modding community.
|
||||
|
||||
### Server Loop
|
||||
|
||||
```rust
|
||||
// prydain-server/src/server.rs
|
||||
pub struct GameServer {
|
||||
world: World,
|
||||
schedule: Schedule,
|
||||
tick: u64,
|
||||
tick_accumulator: f32,
|
||||
clients: Vec<ClientConnection>,
|
||||
}
|
||||
|
||||
impl GameServer {
|
||||
const TICK_RATE: f32 = 30.0;
|
||||
const TICK_DURATION: f32 = 1.0 / Self::TICK_RATE;
|
||||
|
||||
pub fn update(&mut self, dt: f32) {
|
||||
self.tick_accumulator += dt;
|
||||
|
||||
while self.tick_accumulator >= Self::TICK_DURATION {
|
||||
self.tick_accumulator -= Self::TICK_DURATION;
|
||||
self.tick += 1;
|
||||
|
||||
// Process client inputs/commands
|
||||
for client in &mut self.clients {
|
||||
while let Some(msg) = client.recv_input() {
|
||||
self.apply_input(client.player_entity, &msg);
|
||||
}
|
||||
while let Some(cmd) = client.recv_command() {
|
||||
self.apply_command(&cmd);
|
||||
}
|
||||
}
|
||||
|
||||
// Run simulation
|
||||
self.schedule.run(&mut self.world);
|
||||
|
||||
// Send snapshots
|
||||
let snapshot = self.generate_snapshot();
|
||||
for client in &mut self.clients {
|
||||
client.send_snapshot(&snapshot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
- Server runs standalone (headless)
|
||||
- Multiple clients can connect
|
||||
- Simulation is deterministic
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Mod System (Fennel + pxl8)
|
||||
|
||||
**Goal**: Mods run on client via pxl8/LuaJIT, send commands to server.
|
||||
|
||||
### Mod API (extends existing pxl8 Lua API)
|
||||
|
||||
The existing pxl8 API (`pxl8.world_*`, `pxl8.sfx_*`, etc.) is extended with entity functions. Client/server split is an implementation detail—mods just call `pxl8.*`:
|
||||
|
||||
```fennel
|
||||
;; Entity management (server handles if networked)
|
||||
(pxl8.entity_spawn :cauldron-born {:x 10 :y 0 :z 15})
|
||||
(pxl8.entity_damage target-id 25)
|
||||
(pxl8.entity_move_to entity-id {:x 50 :z 50})
|
||||
|
||||
;; Query entity state (from latest snapshot if networked)
|
||||
(pxl8.entity_get_pos entity-id) ; → {:x _ :y _ :z _}
|
||||
(pxl8.entity_query {:range 100 :type :mob})
|
||||
(pxl8.player_entity)
|
||||
|
||||
;; Effects (always local, immediate)
|
||||
(pxl8.sfx_play_note ...) ; existing API
|
||||
(pxl8.particles_emit ...) ; existing API
|
||||
(pxl8.camera_shake 0.5) ; new
|
||||
```
|
||||
|
||||
This matches the existing pattern:
|
||||
```lua
|
||||
pxl8.world_render(w, camera_pos)
|
||||
pxl8.sfx_compressor_create(...)
|
||||
pxl8.particles_update(ps, dt)
|
||||
```
|
||||
|
||||
### Mod Structure (prydain example)
|
||||
|
||||
```
|
||||
prydain/
|
||||
cart.fnl # Mod manifest
|
||||
main.fnl # Entry point
|
||||
mod/
|
||||
entities.fnl # Entity archetype definitions
|
||||
combat.fnl # Combat logic
|
||||
ai/
|
||||
patrol.fnl
|
||||
chase.fnl
|
||||
res/
|
||||
models/
|
||||
textures/
|
||||
sounds/
|
||||
```
|
||||
|
||||
### Entity Definition
|
||||
|
||||
```fennel
|
||||
;; prydain/mod/entities.fnl
|
||||
(def cauldron-born
|
||||
{:archetype :cauldron-born
|
||||
:model "res/models/cauldron_born.glb"
|
||||
:stats {:health 45 :damage 12 :speed 2.5}
|
||||
:behavior :undead-warrior
|
||||
:sounds {:alert :undead-alert :attack :sword-swing}})
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
- `pxl8 prydain/` runs the mod
|
||||
- Fennel script spawns entity (command reaches server)
|
||||
- Entity appears (snapshot received, model rendered)
|
||||
- AI behavior runs, entity patrols/chases
|
||||
|
||||
---
|
||||
|
||||
## Spike Milestones
|
||||
|
||||
| Milestone | Description | Validates |
|
||||
|-----------|-------------|-----------|
|
||||
| M1 | Reorganize pxl8 into module folders | Build system, no regression |
|
||||
| M2 | Port colormap + dither to C | Basic rendering building blocks |
|
||||
| M3 | Port triangle rasterizer to C | Core rendering path |
|
||||
| M4 | C rasterizer has visual parity with Rust | Full rendering correctness |
|
||||
| M5 | Protocol defined, serialize/deserialize works | Client/server communication |
|
||||
| M6 | Client connects, receives snapshot, renders | End-to-end data flow |
|
||||
| M7 | Rust server runs, sends snapshots | Server implementation |
|
||||
| M8 | Fennel script spawns entity via command | Content scripting |
|
||||
| M9 | Full game loop working | Architecture validated |
|
||||
|
||||
---
|
||||
|
||||
## Files to Modify/Create
|
||||
|
||||
### pxl8 (C) - New Files
|
||||
|
||||
| Path | Description |
|
||||
|------|-------------|
|
||||
| `client/src/gfx/pxl8_cpu.c` | CPU backend (prydain optimizations) |
|
||||
| `client/src/gfx/pxl8_gpu.c` | GPU backend (SDL3_GPU, future) |
|
||||
| `client/src/gfx/pxl8_colormap.c/h` | 64×256 lighting LUT |
|
||||
| `client/src/gfx/pxl8_dither.c/h` | Bayer dithering |
|
||||
| `client/src/math/pxl8_simd.h` | SIMD abstractions |
|
||||
| `client/src/net/pxl8_protocol.h` | Message definitions |
|
||||
| `client/src/net/pxl8_net.c/h` | Networking |
|
||||
| `client/src/lua/pxl8/entity.lua` | Entity API (extends pxl8) |
|
||||
|
||||
### pxl8 (C) - Files to Move
|
||||
|
||||
| From | To |
|
||||
|------|-----|
|
||||
| `src/pxl8_gfx.c/h` | `client/src/gfx/pxl8_gfx.c/h` |
|
||||
| `src/pxl8_sfx.c/h` | `client/src/sfx/pxl8_sfx.c/h` |
|
||||
| `src/pxl8_script.c/h` | `client/src/script/pxl8_script.c/h` |
|
||||
| `src/pxl8_hal.h` | `client/src/hal/pxl8_hal.h` |
|
||||
| `src/pxl8_sdl3.c/h` | `client/src/hal/pxl8_sdl3.c/h` |
|
||||
| `src/pxl8_bsp.c/h` | `client/src/world/pxl8_bsp.c/h` |
|
||||
| `src/pxl8_math.c/h` | `client/src/math/pxl8_math.c/h` |
|
||||
| `src/lua/*` | `client/src/lua/*` |
|
||||
|
||||
### prydain - Becomes a Mod
|
||||
|
||||
Current prydain Rust code gets split:
|
||||
|
||||
| Current | Target | Notes |
|
||||
|---------|--------|-------|
|
||||
| `src/gfx/backend/cpu/` | `pxl8/src/gfx/` | Port to C pxl8 |
|
||||
| `src/gfx/display.rs` | DELETE | Use pxl8 HAL |
|
||||
| `src/game/systems/*.rs` | `pxl8/server/` | Generic bevy_ecs server |
|
||||
| `src/game/entities/*.rs` | `prydain/mod/*.fnl` | Convert to Fennel |
|
||||
|
||||
**prydain becomes just a mod:**
|
||||
```
|
||||
prydain/
|
||||
cart.fnl # Manifest
|
||||
main.fnl # Entry point
|
||||
mod/
|
||||
entities.fnl # Entity definitions
|
||||
combat.fnl # Combat logic
|
||||
ai/
|
||||
patrol.fnl
|
||||
chase.fnl
|
||||
quests/
|
||||
main_quest.fnl
|
||||
res/
|
||||
models/
|
||||
textures/
|
||||
sounds/
|
||||
levels/
|
||||
```
|
||||
|
||||
**pxl8 gains:**
|
||||
```
|
||||
pxl8/
|
||||
client/ # C client (existing + ported renderer)
|
||||
src/
|
||||
gfx/ # Including new rasterizer from prydain
|
||||
lua/ # Existing + new entity.lua
|
||||
net/ # NEW: networking
|
||||
...
|
||||
include/
|
||||
meson.build
|
||||
server/ # NEW: Rust bevy_ecs generic server
|
||||
Cargo.toml
|
||||
src/
|
||||
lib.rs
|
||||
server.rs
|
||||
protocol.rs
|
||||
systems/
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue