Logo with title ".Blog"

Briefs

Low-effort content for certain microblogging platforms.

Rx

Ripped a standalone version of @Quenty’s Rx module out of Nevermore. Looks very very promising.

Interfacing with Fusion’s Value objects is really easy:

function Rxf.value(value: Fusion.Value): Rx.Observer
	return Rx.observer(function(sub: Rx.Subscriber): Maid.Task
		local conn = Fusion.Observer(value):onChange(function()
			sub:Fire(value:get())
		end)
		sub:Fire(value:get())
		return conn
	end)
end

How’s performance? I’ve been looking to write a version of what you’re writing here for a while, but query performance seems scary.

Using RxInstanceUtils for now, but this is looking a lot cleaner.

@Quenty, 7:13 PM · Oct 17, 2022

I haven’t deliberately optimized anything, but it’s not the worst. I might be comfortable with one query that updates every frame, for example. It’s a mess, but you can play with it here.

hey wait a minute, arent you not a fan of observing any kind of behavior on instances that enter the data model?

@Kampfkarren, 7:14 PM · Oct 17, 2022

That’s right. Which is why Rx is great, because it simplifies a bunch of boilerplate that would otherwise be need to ensure that an observation is correct.

Metatables suck

In response to Metatables suck.

Metatables: I use metatables to signal the separation of data and behavior. Data goes in the table, behavior goes in the metatable. Great for debugging; the debugger isn’t cluttered with a bunch of methods.

Encapsulation: I don’t actually want true encapsulation, because it’s harder to debug. Unlike local variables, private fields can be tapped into, and I don’t have to hunt them down in the debugger. Also makes writing tests easier.

Overloading: I agree in principal, but in practice, sometimes the convenience is too much to pass up. To reconcile this, I always accompany a non-obvious metamethod behavior with an equivalent method.

But it’s worth noting that metamethods are harder to debug, because they don’t allow yielding, so you can’t set breakpoints in them. That’s why it’s good to have a regular method-based equivalent.

In no particular order:

  • lens flares
  • lowercase archivable property
  • hidden attribute types
  • data transfer over physics
  • Instance.Lock/Unlock
  • /sc == ROOT
  • DebugId can overflow
  • UniqueId epoch
  • roblox.xsd
  • <External> tag
  • true purpose of Geometry service
  • preliminary status
  • preprocessor syntax
  • editable object browser summaries
  • GC only collects instance’s userdata
  • comic sans ui
  • runaway wait() throttling
  • property names can have any character
  • userdata keys in global environment
  • undead Authoring class
  • fast child removal
  • GuiText
  • GuiMain
  • GuiRoot/GuiItem
  • LoadingGui
  • PlayerHUD
  • PseudoPlayer
  • ParallelRampPart
  • PrisimPart
  • PyramidPart
  • RightAngleRampPart
  • QDir/QFont types
  • SystemAddress type
  • __gc attack vector
  • string.rep attack vector
  • debug.loadmodule
  • gameserver.ashx
  • DeployHistory.txt
  • WritePlayerSecurity
  • BasePart.siz
  • DraggingV1
  • MouseButton1DownConnectionCount
  • .mesh girl
  • application/x-roblox-studio
  • loadfile security context
  • bytecode environment injection
  • connectFirst/connectLast
  • studio verbs
  • TextBox.Confidential
  • OverrideCoreScripts
  • DefaultWaitTime
  • ypcall
  • NaN FoV void
  • self-returning modules leak
  • DataModel.Loaded conflict
  • overloaded ScriptContext.AddCoreScript
  • extra KeyCode.KeypadEquals enum items
  • second CameraMode enum
  • second Pages class
  • “Property” type

preprocessor syntax: In older versions of studio, having a $ at the start of a script would highlight the first line in red. Later, when custom highlight colors were added, this was referenced with the Preprocessor Color property, even though it was unused.

self-returning modules leak: If a module returns a value that contains a reference to the module (return script, return {script}, etc), then it will never be GC’d.

How poorly do metrics have to be misinterpreted to reach the conclusion that a developer is creating an entire new game from scratch every single time they open the baseplate?

Today on roblox dev: everyone learns the difference between inventions and discoveries.

Protip: task.delay returns the delayed thread, making cancelable delays trivial.

local thread = task.delay(10, print, "Hi!")
task.wait(5)
task.cancel(thread)

Maid connect

Justifying a Connect method on maids.

-- Regular method.
if maid:Alive() then
	maid.heartbeat = RunService.Heartbeat:Connect(function(dt)
		print("delta time", dt)
	end)
end

-- Method if your name is Max.
maid.heartbeat = if maid:Alive() then
	RunService.Heartbeat:Connect(function(dt)
		print("delta time", dt)
	end) else nil

-- Connect method.
maid:Connect("heartbeat", RunService.Heartbeat, function(dt)
	print("delta time", dt)
end)

Maintenance

If you maintain a popular project, and you’re going on hiatus, are too busy, or just don’t feel like maintaining it right now/anymore, please let your users know.

Marketing

Getting annoyed by projects that market themselves like they’re ready but don’t even have basic documentation.

Reservations

Discord, Snapchat, Instagram: We’re sorry, all of our lawsuit reservations have been filled.

Biometrics

Fingerprint scanning is literally leaving your password, which you can never change, on everything you have ever touched, or will ever touch. And don’t forget about all those pictures that incidentally contain your fingers in immaculate detail.

Foliage

Playing with foliage. Here we have the same texture, triangle count, and triangle size, but different scaling of the base shape, which is a sphere in this case. Unfortunately, it’s hard to get something that looks good without fine-tuning each of these parameters.

Plugin UX

Plugin development should share the same UX as games. Specifically asset management.

Plugin windows

UI refresh allows plugin windows to be docked to the center area. +10000 points.

Last update fixed problems with studio forgetting plugin dock positions. UI refresh is 100% better now.

Gamejam

Not at RDC, but I thought I’d gamejam anyway. Didn’t finish, but I still had fun. Here’s what would have been the thumbnail:

If you’re going to solojam, try to use existing assets as much as possible. I modeled the car, sun, and skybox from scratch, which was fun to do, but sunk way too much time.

Studio cookies

If you have tooling that makes use of Studio’s cookies, Roblox recently changed how they work in Windows. Cookies are no longer stored in the registry, and are instead stored as Credentials:

  • Studio stores the https://www.roblox.com:RobloxStudioAuthCookies credential.
  • Its value is a ; separated list of cookie names (rather, each name has a ; appended, note the trailing ;).
  • The value of each cookie is stored as a credential named https://www.roblox.com:RobloxStudioAuth + the cookie name.

Tooling will still be able to access these cookies just fine. There’s a winapi for it, so most languages will likely have a library for it. I listed some in another tweet.

Relevant libraries for some random languages:

Archivable

Boring Facts: The lowercase “archivable” property can be used within a model or place file to load an instance with Archivable set to false.

Ice cream

Your cashier gives you three dimes and a nickel as your change. Do you:

  • Put it in the tip jar
  • Put it in the charity bin
  • Put it in a locked safe because it’s so much money you can’t imagine spending it even on something you use every day

@BoatbomberRBLX, 2:32 AM · Aug 12, 2022

??? it goes in the paper cup where it is eventually used to extract exact change when buying ice cream at the drive thru

More accurately:

  1. Buy plugin
  2. It turns out to be shit
  3. Could have been ice cream

Passive voice

I use passive voice for references for a formal and well-defined feeling, and active voice for guides/tutorials to feel more loose and relaxed. Strikes a good balance.

DUEH

DUEHs quietly so as not to wake mom and dad