HNHacker News
TopNewBestAskShowJobs

nobu-mori

37 karma · joined December 2, 2022

Building TimewarpDB

nobu _at_ mori.enterprises

submissionscomments
nobu-mori··on Ambient: The Multiplayer Game Engine
What are the guarantees about the networking? I saw this in the blog post:

> The server state is automatically synchronized to clients, and the data model is the same on the server and client. This means that in the future you can move your code between backend and frontend, or even run it on both seamlessly.

Different types of games need different types of networking. It seems like it's going to be hard to reason about how to program the game without knowing the constraints and guarantees on the network code.

nobu-mori··on New headless Chrome has been released and has a near-perfect browser fingerprint
https://bugs.chromium.org/p/chromium/issues/detail?id=706008

It looks like the new headless mode does support extensions.

nobu-mori··on New headless Chrome has been released and has a near-perfect browser fingerprint
Now that headless mode is a "real" Chromium instance, is it possible to add extension support to Chrome running in headless mode?
nobu-mori··on GPTZero Case Study – Exploring False Positives
That's great! All we need to do is negate the output and it will be more accurate.
nobu-mori··on Amazon Takes a 50% Cut of Seller's Revenue
Digital goods have very low marginal unit costs compared to physical goods.
nobu-mori··on Why Firms Are Struggling with the U.S. Economy’s Soft Landing
The article talks only about nominal wage increases. It also has this gem:

> Due to the transient nature of pandemic inflation...

Real wages, overall, are decreasing: https://www.bls.gov/news.release/realer.nr0.htm

> Real average hourly earnings for all employees decreased 0.2 percent from December to January, seasonally adjusted

> Real average hourly earnings decreased 1.8 percent, seasonally adjusted, from January 2022 to January 2023

nobu-mori··on ChatGPT-3: Google Says AI Generated Contents Are Against Webmaster Guidelines
This is definitely a valid concern. OpenAI did extensive data grooming to ensure high-quality inputs were used as training data. They went out of their way, for instance, to attempt to remove auto-translated content.

One interesting thing is that the situation you describe provides a huge moat for the first successful system. For instance, OpenAI can store and fingerprint all of the output from GPT-3 and ChatGPT. They can use these fingerprints to prevent training newer versions of GPT on old outputs. Less popular systems won't be able to sanitize the training data as well.

nobu-mori··on You might not need a CRDT
The case where User B navigates to cursor offset 0 as User A inserts at position 0 is actually easy because User B's cursor can just stay at 0. A harder case would be where User B moves to cursor offset X while User A removes text between (Y, Z) where 0 < Y < Z < X. How that situation gets handled is up to the application developer.

I'm not familiar with OT specifically, but the text editor I'm working on is just a proof-of-concept for the database. The database I'm building is designed to make it very easy to program very complicated multi-player scenarios, although it requires a little work to think of conflict resolution.

nobu-mori··on You might not need a CRDT
The basic prototype I have right now works like this:

The data model has this type in TypeScript:

    {
        text: string;
        cursors: {
            [userId]: {
                offset: number;
            }
        };
    }
Basically, the data model is a string of text and a set of cursors, one for each user. The cursors contain an offset into the text where each user is editing.

When a user connects, the `user-connected` event is handled by setting the cursor position for that user to offset 0. When a user presses a key, an `insert-text` event is sent. The event handler for `insert-text` looks at the user's cursor position and inserts the text at that position and increases the user's cursor. Then, the event handler looks at all the cursors. Each cursor that has an offset greater than the location of the inserted text gets incremented by the length of the inserted text. Removal works the same way, but it removes text and decrements cursor offsets instead. When a user disconnects, the `user-disconnected` event handler removes the cursor to keep the total data size bounded.

As an example, let's say the text was "cat boy" and User A has cursor offset 0 and User B has cursor offset 4. Imagine User A inserts "dog" just a moment before User B inserts "girl", e.g. User B sends `insert-text: "girl"`. The first time this event gets applied, "girl" gets inserted at offset 4. When User A's insertion of "dog" arrives, the insertion of "girl" gets undone and then "dog" is inserted. After "dog" is inserted, User B's cursor is now at offset 7. So when `insert-text: "girl"` is re-applied, "girl" gets inserted at offset 7 and the final text is the same.

One thing I like about this system is that it's very simple. My prototype is like a collaborative notepad. The logic for state updates is only 100 lines long, including a lot of boiler plate for the event handlers (each is an interface implementation).

nobu-mori··on You might not need a CRDT
I agree. Everything should be collaborative. Feel free to reach out if you're interested in collaborating (email in my HN profile). I'm trying to get a v0 of this database out now, and building desirable use-cases is super important.
nobu-mori··on You might not need a CRDT
CRDTs have been on HN a lot recently. I'm working on a database that deals in events rather than raw data. Application developers specify event handlers in JavaScript. The database layer then takes the event handlers and distributes them to the clients. Clients receive the raw stream of events and reconcile the final data state independently. The key aspect is all the event handlers are reversible. This allows clients to insert locally generated events immediately. If any remote events are received out-of-order, the client can undo events, insert the new events, and reapply everything on top of the new state.

I'm curious how many people have a need for solving the real-time multi-player use case. The database I'm working on was inspired by the networking code used in fighting games (rollback netcode), but I'm always curious to learn about additional use cases.

nobu-mori··on Using CRDTs for multiplayer text editing
That looks cool. Thanks for sharing. Rust's enums and match syntax make the API look pretty slick. What types of applications are you seeing people use Aper for?
nobu-mori··on Using CRDTs for multiplayer text editing
I'm developing a new type (AFAIK) of database that makes many types of real-time multi-player use-cases really easy to implement. The original idea came from implementing something called "rollback netcode" in multi-player video games, but the technique works for all types of applications.

Traditional databases (e.g. sql databases and key-value stores) treat the database as a blob of data. This makes multi-player updates very difficult, as reconciling differences in real-time is a hard problem, hence the invention of CRDTs. My new database, however, treats the data as a series of events. In the example of a text editor, the stream of events might be something like: User 1 connected, User 1 pressed key a, User 2 connected, User 2 pressed b, User 1 disconnected, etc.

In addition to the stream of events, application developers also provide an "engine" that converts the stream of events into a blob of data. The engine runs locally on each connected client. When a client connects to the database, they fetch the engine from the database server. The client then receives the stream of events from the database server in real-time. When a client generates an event, it gets inserted into the local engine immediately and also gets broadcasted to the server. The server then broadcasts the event to other connected clients.

The most important part that makes this work comes from a technique called rollback netcode. Events in the stream are ordered and undo-able. When a connected client generates an event, they insert it into their local engine immediately, but other clients are also generating events simultaneously. If all clients optimistically inserted events locally, the event order would differ across clients. To solve this, the engine automatically will undo events when new events come in from the server. The engine then applies the received event in its proper place and reapplies all the undone events on top. The result is that all users have a consistent view of the data.

The logic of an engine looks something like this:

1) When User X connected, set X's cursor position to offset 0.

2) When User X types a letter, insert text at User X's cursor offset and increase User X's cursor offset by 1. Also increment the cursor offset of all other connected users if their cursor offset is > User X's.

And that's it for a basic insert-only text editor. You can see that applying all the events in order yields the correct state. Adding a moveable cursor and the ability to remove text is also trivial. Basically just the opposite of 1 and 2 above. The whole engine can be implemented in like 100 lines of code and is very easy to reason about.