I can't help but over-optimize. We're parsing the result of class.getName(),
it will be a bare class name if not in the array.
Also: Stop going out of our way to not throw an exception if the input
is malformed, as that's the desired result for bad input.
Add three defenses to the Streamable deserialization system to prevent
exploitation by hacked clients:
- Class whitelist: ObjectInputStream.setAllowedClassPrefixes() validates
class names before Class.forName(), blocking arbitrary class loading
from crafted wire data. Callers configure at startup; unconfigured
streams retain existing behavior for backward compatibility.
- Container size caps: BasicStreamers.validateSize() rejects arrays,
collections, and maps with negative or >65536 element counts. Prevents
OOM from a small frame declaring a massive allocation. Applied to all
12 array/collection read paths and Streamer.ArrayStreamer.
- Recursion depth limit: ObjectInputStream.readObject() tracks nesting
depth and throws at 32 levels, preventing stack overflow from
maliciously nested structures (e.g., list-of-list-of-list).
Some networks will kill connections sooner than 60s, especially if they are not using keepalive. This fix should reduce the random disconnects some players experience
I don't think anything is directly streaming these over the wire, but it would
have worked before, so we'll try to keep it working now to avoid unpleasant
surprises.
- It would update if an AttributeChangedEvent was received, but not an
ElementUpdatedEvent!
- If you have 50 fields and 50 editors, then every one was updating
whenever an event arrived? Filter by the field that actually changed?
Does this break something?
A balance between: This is obnoxious, I should fix it in my subclass
and/or we should be compositing functionality, not subclassing... but
adding a time zone to this old thing seems fundamental anyway and this
is an easy fix.
This is used on multi-noded servers so that I can have a service
interface for talking to the node in charge of a particular resource,
and use the same code path even if that node is the current node.
Perhaps this be more smoothly integrated in the future but for now it's
a static utility you need to manually set up.
ProjectX uses Guice to inject dependencies and this results in some random
manager having a dependency on the concrete server class, which invariably is
getting inject itself at the time this dependency has to be resolved, which
causes circular dependencies.
Guice was able to thread the needle with other sneaky business in some cases,
but also sometimes not. So let's give it a nice interface that it can proxy to
manage this particular circular dependency.
ObjectEditorPanel now looks up a static String constant named
FIELD_NAME_TIP (e.g. myField → MY_FIELD_TIP) on the ConfigObject after
calling getEditor(), and sets it as a tooltip on the editor panel.
No changes to ConfigObject's API — existing getEditor() overrides
continue to work and automatically receive tooltips.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>