You've already forked Nitro_Render_V3
mirror of
https://github.com/duckietm/Nitro_Render_V3.git
synced 2026-06-19 15:06:20 +00:00
🆙 Patch GlTextureSystem & Fix effects like BBRed
- Monkey-patch the renderer's GlTextureSystem to prevent crashes from destroyed textures
This commit is contained in:
@@ -291,8 +291,6 @@ export class AvatarImage implements IAvatarImage, IAvatarEffectListener
|
||||
clear: true
|
||||
});
|
||||
|
||||
container.destroy();
|
||||
|
||||
//@ts-ignore
|
||||
this._activeTexture.source.hitMap = null;
|
||||
|
||||
@@ -585,7 +583,7 @@ export class AvatarImage implements IAvatarImage, IAvatarEffectListener
|
||||
this._effectIdInUse = -1;
|
||||
}
|
||||
|
||||
if(effectChanged) this._cache.disposeInactiveActions();
|
||||
if(effectChanged) this._cache.disposeInactiveActions(0);
|
||||
|
||||
if(this._lastActionsString != this._currentActionsString)
|
||||
{
|
||||
@@ -653,6 +651,11 @@ export class AvatarImage implements IAvatarImage, IAvatarEffectListener
|
||||
if(animation.hasDirectionData()) this._directionOffset = animation.directionData.offset;
|
||||
|
||||
if(animation.hasAvatarData()) this._avatarSpriteData = animation.avatarData;
|
||||
|
||||
if(!this._isAnimating && (animation.spriteData?.length > 0 || animation.hasAvatarData()))
|
||||
{
|
||||
this._isAnimating = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ interface IWindowReflectionAvatarState
|
||||
id: number;
|
||||
texture: Texture;
|
||||
location: IVector3D;
|
||||
verticalOffset: number;
|
||||
}
|
||||
|
||||
export class RoomWindowReflectionState
|
||||
@@ -14,7 +15,7 @@ export class RoomWindowReflectionState
|
||||
private static _avatars: Map<number, IWindowReflectionAvatarState> = new Map();
|
||||
private static _updateId: number = 0;
|
||||
|
||||
public static setAvatar(id: number, texture: Texture, location: IVector3D): void
|
||||
public static setAvatar(id: number, texture: Texture, location: IVector3D, verticalOffset: number = 0): void
|
||||
{
|
||||
if(!texture || !location) return;
|
||||
|
||||
@@ -25,7 +26,8 @@ export class RoomWindowReflectionState
|
||||
this._avatars.set(id, {
|
||||
id,
|
||||
texture,
|
||||
location: storedLocation
|
||||
location: storedLocation,
|
||||
verticalOffset
|
||||
});
|
||||
|
||||
// Always bump updateId so reflected walk cycles stay frame-synced
|
||||
|
||||
@@ -76,6 +76,7 @@ export class AvatarVisualization extends RoomObjectSpriteVisualization implement
|
||||
private _isAvatarReady: boolean;
|
||||
private _needsUpdate: boolean;
|
||||
private _geometryUpdateCounter: number;
|
||||
private _reflectionVerticalOffset: number;
|
||||
|
||||
private _additions: Map<number, IAvatarAddition>;
|
||||
|
||||
@@ -127,6 +128,7 @@ export class AvatarVisualization extends RoomObjectSpriteVisualization implement
|
||||
this._isAvatarReady = false;
|
||||
this._needsUpdate = false;
|
||||
this._geometryUpdateCounter = -1;
|
||||
this._reflectionVerticalOffset = 0;
|
||||
|
||||
this._additions = new Map();
|
||||
}
|
||||
@@ -307,7 +309,7 @@ export class AvatarVisualization extends RoomObjectSpriteVisualization implement
|
||||
sprite.offsetX = ((((-1 * scale) / 2) + _local_20[0]) - ((sprite.texture.width - scale) / 2));
|
||||
sprite.offsetY = (((-(sprite.texture.height) + (scale / 4)) + _local_20[1]) + this._postureOffset);
|
||||
}
|
||||
|
||||
|
||||
if(this._isLaying)
|
||||
{
|
||||
if(this._layInside) sprite.relativeDepth = -0.5;
|
||||
@@ -329,8 +331,6 @@ export class AvatarVisualization extends RoomObjectSpriteVisualization implement
|
||||
}
|
||||
}
|
||||
|
||||
this.updateWindowReflectionSource();
|
||||
|
||||
const typingBubble = this.getAddition(AvatarVisualization.TYPING_BUBBLE_ID) as TypingBubbleAddition;
|
||||
|
||||
if(typingBubble)
|
||||
@@ -451,6 +451,17 @@ export class AvatarVisualization extends RoomObjectSpriteVisualization implement
|
||||
_local_21++;
|
||||
}
|
||||
}
|
||||
|
||||
const avatarSprite = this.getSprite(AvatarVisualization.SPRITE_INDEX_AVATAR);
|
||||
|
||||
if(avatarSprite?.texture)
|
||||
{
|
||||
const baseOffsetY = (-(avatarSprite.texture.height) + (scale / 4));
|
||||
|
||||
this._reflectionVerticalOffset = avatarSprite.offsetY - baseOffsetY;
|
||||
}
|
||||
|
||||
this.updateWindowReflectionSource();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1007,7 +1018,7 @@ export class AvatarVisualization extends RoomObjectSpriteVisualization implement
|
||||
|
||||
if(sprite?.texture)
|
||||
{
|
||||
RoomWindowReflectionState.setAvatar(this.object.id, sprite.texture, this.object.getLocation());
|
||||
RoomWindowReflectionState.setAvatar(this.object.id, sprite.texture, this.object.getLocation(), this._reflectionVerticalOffset);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,8 +91,8 @@ export class RoomPlane implements IRoomPlane
|
||||
private _windowMasks: { leftSideLoc: number; rightSideLoc: number }[] = [];
|
||||
private _lastWindowReflectionUpdateId: number = -1;
|
||||
private _windowReflectionFirstSeenAt: Map<number, number> = new Map();
|
||||
private _windowReflectionLastVisible: Map<number, { texture: Texture; location: IVector3D }> = new Map();
|
||||
private _windowReflectionFadeOut: Map<number, { texture: Texture; location: IVector3D; startedAt: number }> = new Map();
|
||||
private _windowReflectionLastVisible: Map<number, { texture: Texture; location: IVector3D; verticalOffset: number }> = new Map();
|
||||
private _windowReflectionFadeOut: Map<number, { texture: Texture; location: IVector3D; verticalOffset: number; startedAt: number }> = new Map();
|
||||
|
||||
constructor(origin: IVector3D, location: IVector3D, leftSide: IVector3D, rightSide: IVector3D, type: number, usesMask: boolean, secondaryNormals: IVector3D[], randomSeed: number, textureOffsetX: number = 0, textureOffsetY: number = 0, textureMaxX: number = 0, textureMaxY: number = 0)
|
||||
{
|
||||
@@ -884,8 +884,8 @@ export class RoomPlane implements IRoomPlane
|
||||
const container = new Container();
|
||||
const visibleAvatarIds = new Set<number>();
|
||||
|
||||
const addReflectionSprite = (texture: Texture, location: IVector3D, alpha: number): boolean => {
|
||||
if(!texture?.source || !location || alpha < 0) return false;
|
||||
const addReflectionSprite = (texture: Texture, location: IVector3D, alpha: number, verticalOffset: number = 0): boolean => {
|
||||
if(!texture?.source || texture.source.destroyed || !texture.source.style || !location || alpha < 0) return false;
|
||||
|
||||
const relative = Vector3d.dif(location, this._location);
|
||||
const planeDistance = Math.abs(Vector3d.scalarProjection(relative, this._normal));
|
||||
@@ -906,7 +906,7 @@ export class RoomPlane implements IRoomPlane
|
||||
if(!closestMask || (closestMask.score > 3)) return false;
|
||||
|
||||
const x = (canvasWidth - ((canvasWidth * leftSideLoc) / this._leftSide.length));
|
||||
const y = (canvasHeight - ((canvasHeight * rightSideLoc) / this._rightSide.length));
|
||||
const y = (canvasHeight - ((canvasHeight * rightSideLoc) / this._rightSide.length)) + verticalOffset;
|
||||
|
||||
const sprite = new Sprite(texture);
|
||||
sprite.anchor.set(0.5, 1);
|
||||
@@ -922,7 +922,7 @@ export class RoomPlane implements IRoomPlane
|
||||
|
||||
for(const avatar of avatars)
|
||||
{
|
||||
if(!avatar?.texture?.source || !avatar.location) continue;
|
||||
if(!avatar?.texture?.source || avatar.texture.source.destroyed || !avatar.texture.source.style || !avatar.location) continue;
|
||||
|
||||
let firstSeenAt = this._windowReflectionFirstSeenAt.get(avatar.id);
|
||||
|
||||
@@ -935,7 +935,7 @@ export class RoomPlane implements IRoomPlane
|
||||
const progress = (elapsed / fadeDurationMs);
|
||||
const alpha = (0.4 * progress);
|
||||
|
||||
if(!addReflectionSprite(avatar.texture, avatar.location, alpha)) continue;
|
||||
if(!addReflectionSprite(avatar.texture, avatar.location, alpha, avatar.verticalOffset || 0)) continue;
|
||||
|
||||
if(!this._windowReflectionFirstSeenAt.has(avatar.id)) this._windowReflectionFirstSeenAt.set(avatar.id, firstSeenAt);
|
||||
|
||||
@@ -947,7 +947,8 @@ export class RoomPlane implements IRoomPlane
|
||||
|
||||
this._windowReflectionLastVisible.set(avatar.id, {
|
||||
texture: avatar.texture,
|
||||
location: storedLocation
|
||||
location: storedLocation,
|
||||
verticalOffset: avatar.verticalOffset || 0
|
||||
});
|
||||
}
|
||||
|
||||
@@ -955,7 +956,7 @@ export class RoomPlane implements IRoomPlane
|
||||
{
|
||||
if(visibleAvatarIds.has(id) || this._windowReflectionFadeOut.has(id)) continue;
|
||||
|
||||
if(!lastVisible.texture?.source)
|
||||
if(!lastVisible.texture?.source || lastVisible.texture.source.destroyed || !lastVisible.texture.source.style)
|
||||
{
|
||||
this._windowReflectionLastVisible.delete(id);
|
||||
this._windowReflectionFirstSeenAt.delete(id);
|
||||
@@ -966,6 +967,7 @@ export class RoomPlane implements IRoomPlane
|
||||
this._windowReflectionFadeOut.set(id, {
|
||||
texture: lastVisible.texture,
|
||||
location: lastVisible.location,
|
||||
verticalOffset: lastVisible.verticalOffset,
|
||||
startedAt: now
|
||||
});
|
||||
|
||||
@@ -986,7 +988,7 @@ export class RoomPlane implements IRoomPlane
|
||||
|
||||
const alpha = (0.4 * (1 - (elapsed / fadeDurationMs)));
|
||||
|
||||
if(!addReflectionSprite(fadeOut.texture, fadeOut.location, alpha)) this._windowReflectionFadeOut.delete(id);
|
||||
if(!addReflectionSprite(fadeOut.texture, fadeOut.location, alpha, fadeOut.verticalOffset)) this._windowReflectionFadeOut.delete(id);
|
||||
}
|
||||
|
||||
if(!container.children.length)
|
||||
|
||||
@@ -409,7 +409,7 @@ export class RoomSpriteCanvas implements IRoomRenderingCanvas
|
||||
const texture = sprite.texture;
|
||||
const baseTexture = texture && texture.source;
|
||||
|
||||
if(!texture || !baseTexture || baseTexture.destroyed) continue;
|
||||
if(!texture || !baseTexture) continue;
|
||||
|
||||
const spriteX = ((x + sprite.offsetX) + this._screenOffsetX);
|
||||
const spriteY = ((y + sprite.offsetY) + this._screenOffsetY);
|
||||
|
||||
@@ -29,7 +29,7 @@ export class ExtendedSprite extends Sprite
|
||||
|
||||
public setTexture(texture: Texture): void
|
||||
{
|
||||
if(!texture || texture.source?.destroyed) texture = Texture.EMPTY;
|
||||
if(!texture) texture = Texture.EMPTY;
|
||||
|
||||
if(texture === this.texture) return;
|
||||
|
||||
|
||||
@@ -1,13 +1,57 @@
|
||||
import { AutoDetectOptions, Renderer, autoDetectRenderer } from 'pixi.js';
|
||||
import { AutoDetectOptions, Renderer, Texture, autoDetectRenderer } from 'pixi.js';
|
||||
|
||||
let renderer: Renderer = null;
|
||||
|
||||
const patchGlTextureSystem = (r: Renderer): void =>
|
||||
{
|
||||
const textureSystem = (r as any).texture;
|
||||
|
||||
if(!textureSystem) return;
|
||||
|
||||
const proto = Object.getPrototypeOf(textureSystem);
|
||||
|
||||
if(!proto) return;
|
||||
|
||||
const origUpdateStyle = proto.updateStyle;
|
||||
|
||||
if(origUpdateStyle && !proto.__patchedUpdateStyle)
|
||||
{
|
||||
proto.updateStyle = function(source: any, firstCreation: boolean)
|
||||
{
|
||||
if(!source || source.destroyed || !source.style) return;
|
||||
|
||||
return origUpdateStyle.call(this, source, firstCreation);
|
||||
};
|
||||
|
||||
proto.__patchedUpdateStyle = true;
|
||||
}
|
||||
|
||||
const origBindSource = proto.bindSource;
|
||||
|
||||
if(origBindSource && !proto.__patchedBindSource)
|
||||
{
|
||||
proto.bindSource = function(source: any, location = 0)
|
||||
{
|
||||
if(!source || source.destroyed || !source.style)
|
||||
{
|
||||
source = Texture.EMPTY.source;
|
||||
}
|
||||
|
||||
return origBindSource.call(this, source, location);
|
||||
};
|
||||
|
||||
proto.__patchedBindSource = true;
|
||||
}
|
||||
};
|
||||
|
||||
export const PrepareRenderer = async (options: Partial<AutoDetectOptions>): Promise<Renderer> =>
|
||||
{
|
||||
renderer = await autoDetectRenderer(options);
|
||||
|
||||
renderer.events?.destroy();
|
||||
|
||||
patchGlTextureSystem(renderer);
|
||||
|
||||
return renderer;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user