organized as client/server, started uxn sprite stuff
Iris Lightshard nilix@nilfm.cc
PGP Signature
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEkFh6dA+k/6CXFXU4O3+8IhROY5gFAmEUL70ACgkQO3+8IhRO Y5jfwA/+KOvPFxaf4dbX3w6AKqauGUUsDrAcSPv330/NH1oO6WRDvCSOdsn806e2 +Dk4aZFKBdcaCKI/3osSmK2Fp9bb8mZauN39IWxGO4hx4VE3pWoJ/9Z+EugOvS9m AILbNA9Yu1doS4nD8PfUwhwlOivFZL7BqbbK4olMO2rkR1b+P0h8xqNsgkYPzMsI 0xfvvfp2AYRf7WgJ1Tl1uTWc21JnS1Te75g2zH4lS/C5Dyn8+p5FWomVOYuL1mgt spMKvpKw0wW5Z1a7htbQA9GjqjrhOUbl9tpIzk8QArCkNe3y/+GkOo4h4qrgZdiV LQj00TQNbtRSMx/zTTeqGQ8eRWMn+kMkXE6w4hoZPx9mbrcCDF5crMc22VWmlzkp O4ZtUngYb+4cFka5fGsGMG8owcKr9o+XyrmV2w/SnNjziz8fFcyo/6rtxs3Ml8Hi x4bfz+kZMW5Uv6MlyDaj/u2mFuZck01qbEewhtmGN62bjGizwDiBHeAdvLcAQrug jpgt7WZb+ngAMYyRBOUHBZmLNNny2slQg7AuOaXi3k5ugVlnUSOVhDShGvgIe2Vb d/qTnvX5mFVVmzH5Hp5Li+Oq8huer3Nkr2AXSIDCW/8DvEO5ir3S4WKTGlYqKeN0 M56hI/sI06glj66eQUbi/k56ps5PNvtcTAmS23sFDTwMnnGRJ48= =h01f -----END PGP SIGNATURE-----
29 files changed,
200 insertions(+),
3 deletions(-)
jump to
M
.gitignore
→
.gitignore
@@ -1,3 +1,3 @@
-*.o -xrxs -carts/*/realms/ +server/*.o +server/xrxs +uxn-client/xrxs.rom
A
server/LICENSE
@@ -0,0 +1,8 @@
+Copyright 2021 Derek Stevens + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +
A
server/README.md
@@ -0,0 +1,81 @@
+# xrxs + +`xrxs` is an experimental game server using the Plan 9 protocol `9p`. + +The client is intended to be a specialized [uxn](https://wiki.xxiivv.com/site/uxn.html) ROM that can load other ROMs (possibly preserving its own code to maintain a common menu system or interface to `xrxs`). + +## design + +This is the working structure of the 9p filesystem: + +* `/ctl`: Read/write control file for inputing system commands. Reading the file shows the status of the last input command: 1 for success, 0 for failure; `logout` is a special case, and the status code will be -1 if it was succesful. the following are valid command syntax: + * `login PW`: Authenticate with `xrxs` -- password is hashed against realm password hash. + * `logout`: Gracefully remove yourself from the users table. + * `load CART`: Load a cartridge. + * `chunk TYPE N`: Load data of type TYPE and chunk number N. + * `create REALM`: Create a new realm (start a new game) -- must have a cartridge loaded + * `protect PW`: Protect the curent realm with a password if you are the master. + * `transfer USER`: Transfer ownership of the realm to another user. + * `delete REALM`: Delete the realm off the server if you are the master and it is empty. + * `enter REALM`: Join an existing realm. + * `leave`: Leave the current realm. + * `unload`: Unload the cartridge. + +* `/users`: Read-only; Self and others in the realm are readable from here, one per line. It contains only yourself before joining a realm. Your username on your machine is used as your username in `xrxs` -- if your name is taken, you will get an error on attaching. + +* `/carts`: Available game/app cartridges for this server, read only; Carts are listed per line upon reading the file. It is backed by files on the server in a directory structure like `carts/CART_NAME/{CART_NAME.rom, data/, realms/}`. + +* `/slot`: After loading the cartridge, its ROM is read from here; Read-only. + +* `/data/`: Any supporting data that comes with the cartridge will be found here; They are in three parts: `sprite`, `audio`, and `text`. Because `uxn` is limited to 64-128kb input files, the filesizes of these data blobs should be 64kb max, and the `chunk` command should be used to page different files into the service when needed. The files on the server should be like `TYPEN` where `TYPE` is one of `sprite`, `audio`, and `text`, and `N` is any sequence of characters (canonically a nonnegative integer). When first loading the cartridge, `N == 0`. Issuing the command `chunk TYPE XXX` will attempt to load data from file `carts/CART_NAME/data/TYPEXXX` into the correct data file. If `TYPE` is not one of `sprite`, `audio`, or `text`, or the ifle `TYPEXXX` doesn't exist in the data directory, the `chunk` command does nothing. + +* `/realms`: Open/saved realms, read-only. Realms and their associated universe are backed by real files on the server so that they can be preserved across service instantiations, in a directory structure like: `carts/CART_NAME/realms/REALM_NAME/{realm, universe}`. Realms can either be solo, open, or protected; Open or protected realms can have limited member numbers. Depending on the cartridge, these settings can be user-managed or managed by the cartridge itself. Realms are listed per line upon reading the file like: `REALM_NAME 1 4 1`. First would obviously be the name of the realm. The first number is number of members, second is member limit, third is 1 if protected, 0 if not. `0 1 1` represents a protected solo realm that is empty (saved game with password). `0 1 0` represents an unprotected solo realm that is empty (saved game with no password). + +* `/universe`: Write here to update serverside state for this cart/realm; Read from here to get the complete current state. This is backed by a key-value-pair list on the server. + +* `/scope`: Write here to tell the server the names of the `Atom`s (key/value pair of a `Universe`) you're interested in (one per line), and read from here to retrieve their values (one per line). In many cases this will be preferrable to fetching the entire `Universe`. + +* `/random`: Read-only, get a random number from 0 to 99. + +* `/grandom`: Read-only, get a random number from 0 to 99 -- These are doled out on a per-realm basis, and the number stays the same until everyone in the realm has had a chance to read it. If you've already read it this round or aren't in a realm, it will be empty. + +### realm format + +Each realm directory on the server should have the following files: + + * `realm`: Basic data for the realm, file should contain only the maximum number of members, the master's name, and the password hash, if any (otherwise 0), separated by spaces. + * `universe`: The actual game state for the realm as key value pairs, one per line, like `KEY = VALUE`; limit 15 characters for keys, 63 for values. + +The realm should be synchronized to disc when realm membership, limit, or password change. Fenagling some periodic autosave should be possible... + +## configuration + +`config.h` in the source contains the following configuration macros: + + * `MAX_USERS`: the maximum number of simultaneous users able to attach to the `xrxs` service + * `DATA_DIR`: the path to the root of the cartridge and realm storage; can be absolute or relative to the `xrxs` executable, but must have the trailing `/` + +## build/run + +`xrxs` is built/tested in a Linux environment with `plan9port` and the C standard library as the only dependencies. With minimal modifications it will probably run just as well on Plan9, *BSD, WSL, and MacOS. + +Running `./build.sh` from the repository root should build the `xrxs` executable. + +You can run a local server (for testing, split-screen games, or single-player games) with: + +``` +./xrxs -m /path/to/mountpoint +``` + +or expose a service on the network (uses `9pserve` to support multiple users and gracefully handle disconnects) with: + +``` +./xrxs-srv.sh start +``` + +Similarly, you can stop the service with: + +``` +./xrxs-srv.sh stop +``` +
A
uxn-client/xrxs.tal
@@ -0,0 +1,107 @@
+( utility macros ) + +%+ { ADD } %- { SUB } %* { MUL } %/ { DIV } +%< { LTH } %> { GTH } %= { EQU } %! { NEQ } +%++ { ADD2 } %-- { SUB2 } %** { MUL2 } %// { DIV2 } +%<< { LTH2 } %>> { GTH2 } %== { EQU2 } %!! { NEQ2 } + +%INC-X { .Screen/x DEI2 #0008 ADD2 .Screen/x DEO2 } ( -- ) +%INC-Y { .Screen/y DEI2 #0008 ADD2 .Screen/y DEO2 } ( -- ) + +%CENTER-X { .Screen/width DEI2 #01 SFT2 } +%CENTER-Y { .Screen/height DEI2 #01 SFT2 } + +%MOD { DIVk MUL SUB } +%MOD2 { DIV2k MUL2 SUB2 } + +%NEXT-TILE { DUP2 #0010 ADD2 } + +%DEBUG { ;print-hex JSR2 #0a .Console/write DEO } +%DEBUG2 { SWP ;print-hex JSR2 ;print-hex JSR2 #0a .Console/write DEO } + +%RTN { JMP2r } + +( devices ) + +|00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 &debug $1 &halt $1 ] +|10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ] +|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ] +|30 @Audio0 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] +|40 @Audio1 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] +|50 @Audio2 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] +|60 @Audio3 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ] +|80 @Controller [ &vector $2 &button $1 &key $1 ] +|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ] +|a0 @File [ &vector $2 &success $2 &offset $2 &pad $2 &name $2 &length $2 &load $2 &save $2 ] +|b0 @DateTime [ &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1 ] + +( variables ) + +|0000 + +@state $1 +@cart $64 +@realm $64 + +( program ) + +|0100 ( -> ) + + ( theme ) + #02c1 .System/r DEO2 + #02cd .System/g DEO2 + #02cb .System/b DEO2 + + ;spritesheet .File/name DEO2 + #0100 .File/length DEO2 + + #0000 .File/offset DEO2 + ;uxnlogo .File/load DEO2 + + #0200 .File/offset DEO2 + ;xrxslogo .File/load DEO2 + + ;draw-uxn-logo JSR2 + ;draw-xrxs-logo JSR2 +BRK + +@draw-uxn-logo ( -> ) + + CENTER-X #0020 SUB2 .Screen/x DEO2 + CENTER-Y #0010 SUB2 .Screen/y DEO2 + + #0100 #0000 &while EQU2k ,&end JCN + DUP2 ;uxnlogo ADD2 .Screen/addr DEO2 + #81 .Screen/sprite DEO INC-X + + NEXT-TILE #0040 MOD2 #0000 NEQ2 ,&no-inc-y JCN + CENTER-X #0020 SUB2 .Screen/x DEO2 + INC-Y + &no-inc-y + #0010 ADD2 ,&while JMP &end POP2 POP2 + +RTN + +@draw-xrxs-logo ( -> ) + + CENTER-X .Screen/x DEO2 + CENTER-Y #0010 SUB2 .Screen/y DEO2 + + #0100 #0000 &while EQU2k ,&end JCN + DUP2 ;xrxslogo ADD2 .Screen/addr DEO2 + #81 .Screen/sprite DEO INC-X + + NEXT-TILE #0040 MOD2 #0000 NEQ2 ,&no-inc-y JCN + CENTER-X .Screen/x DEO2 + INC-Y + &no-inc-y + #0010 ADD2 ,&while JMP &end POP2 POP2 + +RTN + +( constants ) +@spritesheet "xrxs.chr 00 + +( sprites ) +@uxnlogo $128 +@xrxslogo $128