Compare commits

...

35 Commits

Author SHA1 Message Date
AlexandreSi
b7fb29b358 Clean package-lock.json 2023-10-11 17:39:42 +02:00
AlexandreSi
daed45461e Override react-refresh version to avoid conflict app running failures 2023-10-11 17:21:17 +02:00
AlexandreSi
f0cad71ac5 Extract logic in hook 2023-10-11 16:14:42 +02:00
AlexandreSi
aef7368e90 Regenerate package lock 2023-10-11 16:07:21 +02:00
AlexandreSi
17127d76ed Fix chokidar version 2023-10-11 16:01:22 +02:00
AlexandreSi
0cae4c5824 Review changes 2023-10-11 16:01:05 +02:00
AlexandreSi
2242b395a0 Simplify extension loading logic 2023-10-11 16:01:01 +02:00
AlexandreSi
118df198ab Fine-tune chokidar 2023-10-11 15:38:45 +02:00
AlexandreSi
bffc8b6190 Prettier 2023-10-11 15:07:20 +02:00
AlexandreSi
43f2582a39 Deactivate interactions in PIXI when the scene is paused 2023-10-11 15:04:40 +02:00
AlexandreSi
dbf916edf6 Review changes 2023-10-11 14:07:17 +02:00
clem
b255409a9f Use correct path and parse windows path 2023-10-11 12:15:18 +02:00
AlexandreSi
62c754e87c Fix flow 2023-10-10 12:53:24 +02:00
AlexandreSi
eb87e84598 Clear resources caches when closing a project 2023-10-09 18:25:01 +02:00
AlexandreSi
4f1b75cacf Add cache clearing method for tilemap objects and use it when reloading resources 2023-10-09 17:54:26 +02:00
AlexandreSi
2c92c1a259 Add possibility to register cache clearing methods for instances renderers 2023-10-09 17:53:49 +02:00
AlexandreSi
9f82842a79 Add method to clear caches 2023-10-09 17:51:28 +02:00
AlexandreSi
69f2d52977 Pause scene rendering when reloading resource 2023-10-09 16:20:44 +02:00
AlexandreSi
26c472002e Add method to EditorDisplay interface to handle scene rendering 2023-10-09 16:14:50 +02:00
AlexandreSi
1965b54726 Clear cache for 3D boxes on resource change 2023-10-09 11:54:05 +02:00
AlexandreSi
fdfa4538ae Clear cache for fonts on resource change 2023-10-06 17:05:19 +02:00
AlexandreSi
9a422a4e03 Clear cache for 3D models on resource change 2023-10-06 16:50:49 +02:00
AlexandreSi
8c6669c88b Debounce callback file-wise 2023-10-06 16:30:29 +02:00
AlexandreSi
b47eb74c16 Use objects collector to reset instance renderers 2023-10-06 15:48:38 +02:00
AlexandreSi
d0487647f6 Add ObjectsWorker to retrieve objects in project that use given resource 2023-10-06 15:48:37 +02:00
AlexandreSi
2b4f4ed871 Expose ProjectBrowserHelper ExposeProjectObjects lethods to JS 2023-10-06 15:48:37 +02:00
AlexandreSi
13988ef533 Update pixi texture and instance renderers for changes to be displayed 2023-10-06 15:48:37 +02:00
AlexandreSi
1d4fc4d333 Add debounce on callback 2023-10-06 15:48:37 +02:00
AlexandreSi
e5924322a6 Move filesystem watching logic to local file storage provider 2023-10-06 15:48:37 +02:00
AlexandreSi
a494731c72 WIP: Clean pixi cache on resource externally changed 2023-10-06 15:48:37 +02:00
AlexandreSi
21e306d853 Add onResourceExternallyChanged callback on scene and events editors 2023-10-06 15:48:37 +02:00
AlexandreSi
84396b8583 Reduce number of needed ref 2023-10-06 15:48:37 +02:00
AlexandreSi
b694d81b27 Transform ResourcePreview component into functional component 2023-10-06 15:48:37 +02:00
AlexandreSi
3907c68f3a Add watcher in mainframe 2023-10-06 15:48:37 +02:00
AlexandreSi
1830180dc0 Install chokidar 2023-10-06 15:48:37 +02:00
52 changed files with 656 additions and 242 deletions

View File

@@ -293,8 +293,8 @@ void ResourceWorkerInObjectsWorker::DoVisitBehavior(gd::Behavior &behavior){
gd::ResourceWorkerInObjectsWorker
GetResourceWorkerOnObjects(const gd::Project &project,
gd::ArbitraryResourceWorker &worker) {
gd::ResourceWorkerInObjectsWorker eventsWorker(project, worker);
return eventsWorker;
gd::ResourceWorkerInObjectsWorker resourcesWorker(project, worker);
return resourcesWorker;
}
} // namespace gd

View File

@@ -0,0 +1,19 @@
#include "ObjectsUsingResourceCollector.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"
namespace gd {
void ObjectsUsingResourceCollector::DoVisitObject(gd::Object& object) {
gd::ResourceNameMatcher resourceNameMatcher(resourceName);
object.GetConfiguration().ExposeResources(resourceNameMatcher);
if (resourceNameMatcher.AnyResourceMatches()) {
objectNames.push_back(object.GetName());
}
};
ObjectsUsingResourceCollector::~ObjectsUsingResourceCollector() {}
} // namespace gd

View File

@@ -0,0 +1,89 @@
/*
* GDevelop Core
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
* reserved. This project is released under the MIT License.
*/
#ifndef ProjectObjectsUsingResourceCollector_H
#define ProjectObjectsUsingResourceCollector_H
#include <vector>
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
#include "GDCore/String.h"
namespace gd {
class Object;
} // namespace gd
namespace gd {
class GD_CORE_API ObjectsUsingResourceCollector
: public ArbitraryObjectsWorker {
public:
ObjectsUsingResourceCollector(const gd::String& resourceName_)
: resourceName(resourceName_){};
virtual ~ObjectsUsingResourceCollector();
std::vector<gd::String>& GetObjectNames() { return objectNames; }
private:
void DoVisitObject(gd::Object& object) override;
std::vector<gd::String> objectNames;
gd::String resourceName;
};
class GD_CORE_API ResourceNameMatcher : public ArbitraryResourceWorker {
public:
ResourceNameMatcher(const gd::String& resourceName_)
: resourceName(resourceName_), matchesResourceName(false){};
virtual ~ResourceNameMatcher(){};
bool AnyResourceMatches() { return matchesResourceName; }
void Reset() { matchesResourceName = false; }
private:
virtual void ExposeFile(gd::String& resource) override{
/*Don't care, we just read resource names*/
};
virtual void ExposeImage(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeAudio(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeFont(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeJson(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeTilemap(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeTileset(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeVideo(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeBitmapFont(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
virtual void ExposeModel3D(gd::String& otherResourceName) override {
MatchResourceName(otherResourceName);
};
void MatchResourceName(gd::String& otherResourceName) {
if (otherResourceName == resourceName) matchesResourceName = true;
}
gd::String resourceName;
bool matchesResourceName;
};
}; // namespace gd
#endif // ProjectObjectsUsingResourceCollector_H

View File

@@ -26,6 +26,7 @@ export type ObjectsRenderingService = {
requireModule: (dirname: string, moduleName: string) => any,
getThumbnail: (project: gdProject, objectConfiguration: gdObjectConfiguration) => string,
rgbOrHexToHexNumber: (value: string) => number,
registerClearCache: (clearCache: any => void) => void,
};
export type ObjectsEditorService = {
registerEditorConfiguration: (objectType: string, editorConfiguration: any) => void,

View File

@@ -1044,7 +1044,9 @@ module.exports = {
.setExtensionInformation(
'TileMap',
_('Tilemap'),
"The Tilemap object can be used to display tile-based objects. It's a good way to create maps for RPG, strategy games or create objects by assembling tiles, useful for platformer, retro-looking games, etc...",
_(
"The Tilemap object can be used to display tile-based objects. It's a good way to create maps for RPG, strategy games or create objects by assembling tiles, useful for platformer, retro-looking games, etc..."
),
'Todor Imreorov',
'Open source (MIT License)'
)
@@ -1061,6 +1063,25 @@ module.exports = {
return extension;
},
registerClearCache: function (
objectsRenderingService /*: ObjectsRenderingService */
) {
const TilemapHelper = objectsRenderingService.requireModule(
__dirname,
'helper/TileMapHelper'
);
const clearCaches = (
project /* InstanceHolder - gdProject in the editor */
) => {
/** @type {TileMapHelper.TileMapManager} */
const manager = TilemapHelper.TileMapManager.getManager(project);
manager.clearCaches();
};
objectsRenderingService.registerClearCache(clearCaches);
},
/**
* You can optionally add sanity tests that will check the basic working
* of your extension behaviors/objects by instantiating behaviors/objects

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
import { LDtkTileMap } from '../load/ldtk/LDtkFormat';
import { TiledTileMap } from '../load/tiled/TiledFormat';
export declare type TileMapFileContent =
export type TileMapFileContent =
| {
kind: 'tiled';
data: TiledTileMap;

View File

@@ -1 +1 @@
{"version":3,"file":"TileMapFileContent.d.ts","sourceRoot":"","sources":["../../src/load/TileMapFileContent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,oBAAY,kBAAkB,GAC1B;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC"}
{"version":3,"file":"TileMapFileContent.d.ts","sourceRoot":"","sources":["../../src/load/TileMapFileContent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,MAAM,MAAM,kBAAkB,GAC1B;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;CACpB,GACD;IACE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;CACnB,CAAC"}

View File

@@ -2,7 +2,7 @@ import { integer } from '../../model/CommonTypes';
/**
* version 1.1.3 - https://github.com/deepnight/ldtk/blob/66fff7199932357f3ab9b044c2fc2a856f527831/docs/JSON_SCHEMA.json
*/
export declare type LDtkTileMap = {
export type LDtkTileMap = {
/** LDtk application build identifier.<br/> This is only used to identify the LDtk version that generated this particular project file, which can be useful for specific bug fixing. Note that the build identifier is just the date of the release, so it's not unique to each user (one single global ID per LDtk public release), and as a result, completely anonymous. */
appBuildId: number;
/** Number of backup files to keep, if the `backupOnSave` is TRUE */
@@ -72,7 +72,7 @@ export declare type LDtkTileMap = {
| null;
};
/** Auto-layer rule group */
declare type LDtkAutoLayerRuleGroup = {
type LDtkAutoLayerRuleGroup = {
/** */
active: boolean;
/** *This field was removed in 1.0.0 and should no longer be used.* */
@@ -87,9 +87,9 @@ declare type LDtkAutoLayerRuleGroup = {
uid: integer;
};
/** This complex section isn't meant to be used by game devs at all, as these rules are completely resolved internally by the editor before any saving. You should just ignore this part. */
declare type LDtkAutoRuleDef = {};
type LDtkAutoRuleDef = {};
/** If you're writing your own LDtk importer, you should probably just ignore *most* stuff in the `defs` section, as it contains data that are mostly important to the editor. To keep you away from the `defs` section and avoid some unnecessary JSON parsing, important data from definitions is often duplicated in fields prefixed with a double underscore (eg. `__identifier` or `__type`). The 2 only definition types you might need here are **Tilesets** and **Enums**. */
declare type LDtkDefinition = {
type LDtkDefinition = {
/** All entities definitions, including their custom fields */
entities: LDtkEntityDef[];
/** All internal enums */
@@ -104,7 +104,7 @@ declare type LDtkDefinition = {
tilesets: LDtkTilesetDef[];
};
/** Entity definition */
declare type LDtkEntityDef = {
type LDtkEntityDef = {
/** Base entity color */
color: string;
/** Array of field definitions */
@@ -166,7 +166,7 @@ declare type LDtkEntityDef = {
width: integer;
};
/** Entity instance */
declare type LDtkEntityInstance = {
type LDtkEntityInstance = {
/** Grid-based coordinates (`[x,y]` format) */
__grid: integer[];
/** Entity definition identifier */
@@ -193,7 +193,7 @@ declare type LDtkEntityInstance = {
width: integer;
};
/** Enum definition */
declare type LDtkEnumDef = {
type LDtkEnumDef = {
/** */
externalFileChecksum: string | null;
/** Relative path to the external file providing this Enum */
@@ -210,7 +210,7 @@ declare type LDtkEnumDef = {
values: LDtkEnumDefValues[];
};
/** Enum value definition */
declare type LDtkEnumDefValues = {
type LDtkEnumDefValues = {
/** An array of 4 Int values that refers to the tile in the tileset image: `[ x, y, width, height ]` */
__tileSrcRect: integer[] | null;
/** Optional color */
@@ -221,14 +221,14 @@ declare type LDtkEnumDefValues = {
tileId: integer | null;
};
/** In a tileset definition, enum based tag infos */
declare type LDtkEnumTagValue = {
type LDtkEnumTagValue = {
/** */
enumValueId: string;
/** */
tileIds: integer[];
};
/** This section is mostly only intended for the LDtk editor app itself. You can safely ignore it. */
declare type LDtkFieldDef = {
type LDtkFieldDef = {
/** Human readable value type. Possible values: `Int, Float, String, Bool, Color, ExternEnum.XXX, LocalEnum.XXX, Point, FilePath`.<br/> If the field is an array, this field will look like `Array<...>` (eg. `Array<Int>`, `Array<Point>` etc.)<br/> NOTE: if you enable the advanced option **Use Multilines type**, you will have \"*Multilines*\" instead of \"*String*\" when relevant. */
__type: string;
/** Optional list of accepted file extensions for FilePath value type. Includes the dot: `.ext` */
@@ -310,7 +310,7 @@ declare type LDtkFieldDef = {
useForSmartColor: boolean;
};
/** Field instance */
declare type LDtkFieldInstance = {
type LDtkFieldInstance = {
/** Field definition identifier */
__identifier: string;
/** Optional TilesetRect used to display this field (this can be the field own Tile, or some other Tile guessed from the value, like an Enum). */
@@ -324,7 +324,7 @@ declare type LDtkFieldInstance = {
/** Editor internal raw values */
realEditorValues: any[];
};
declare type LDtkFlag =
type LDtkFlag =
| 'DiscardPreCsvIntGrid'
| 'ExportPreCsvIntGridFormat'
| 'IgnoreBackupSuggest'
@@ -332,7 +332,7 @@ declare type LDtkFlag =
| 'MultiWorlds'
| 'UseMultilinesType';
/** IntGrid value definition */
declare type LDtkIntGridValueDef = {
type LDtkIntGridValueDef = {
/** */
color: string;
/** User defined unique identifier */
@@ -341,14 +341,14 @@ declare type LDtkIntGridValueDef = {
value: integer;
};
/** IntGrid value instance */
declare type LDtkIntGridValueInstance = {
type LDtkIntGridValueInstance = {
/** Coordinate ID in the layer grid */
coordId: integer;
/** IntGrid value */
v: integer;
};
/** Layer definition */
declare type LDtkLayerDef = {
type LDtkLayerDef = {
/** Type of the layer (*IntGrid, Entities, Tiles or AutoLayer*) */
__type: string;
/** Contains all the auto-layer rule definitions. */
@@ -401,7 +401,7 @@ declare type LDtkLayerDef = {
uid: integer;
};
/** Layer instance */
declare type LDtkLayerInstance = {
type LDtkLayerInstance = {
/** Grid-based height */
__cHei: integer;
/** Grid-based width */
@@ -452,7 +452,7 @@ declare type LDtkLayerInstance = {
visible: boolean;
};
/** This section contains all the level data. It can be found in 2 distinct forms, depending on Project current settings: - If \"*Separate level files*\" is **disabled** (default): full level data is *embedded* inside the main Project JSON file, - If \"*Separate level files*\" is **enabled**: level data is stored in *separate* standalone `.ldtkl` files (one per level). In this case, the main Project JSON file will still contain most level data, except heavy sections, like the `layerInstances` array (which will be null). The `externalRelPath` string points to the `ldtkl` file. A `ldtkl` file is just a JSON file containing exactly what is described below. */
declare type LDtkLevel = {
type LDtkLevel = {
/** Background color of the level (same as `bgColor`, except the default value is automatically used here if its value is `null`) */
__bgColor: string;
/** Position informations of the background image, if there is one. */
@@ -497,7 +497,7 @@ declare type LDtkLevel = {
worldY: integer;
};
/** Level background image position info */
declare type LDtkLevelBgPosInfos = {
type LDtkLevelBgPosInfos = {
/** An array of 4 float values describing the cropped sub-rectangle of the displayed background image. This cropping happens when original is larger than the level bounds. Array format: `[ cropX, cropY, cropWidth, cropHeight ]` */
cropRect: number[];
/** An array containing the `[scaleX,scaleY]` values of the **cropped** background image, depending on `bgPos` option. */
@@ -506,7 +506,7 @@ declare type LDtkLevelBgPosInfos = {
topLeftPx: integer[];
};
/** Nearby level info */
declare type LDtkNeighbourLevel = {
type LDtkNeighbourLevel = {
/** A single lowercase character tipping on the level location (`n`orth, `s`outh, `w`est, `e`ast). */
dir: string;
/** Neighbour Instance Identifier */
@@ -515,7 +515,7 @@ declare type LDtkNeighbourLevel = {
levelUid: integer;
};
/** This structure represents a single tile from a given Tileset. */
declare type LDtkTile = {
type LDtkTile = {
/** Internal data used by the editor.<br/> For auto-layer tiles: `[ruleId, coordId]`.<br/> For tile-layer tiles: `[coordId]`. */
d: integer[];
/** \"Flip bits\", a 2-bits integer to represent the mirror transformations of the tile.<br/> - Bit 0 = X flip<br/> - Bit 1 = Y flip<br/> Examples: f=0 (no flip), f=1 (X flip only), f=2 (Y flip only), f=3 (both flips) */
@@ -528,7 +528,7 @@ declare type LDtkTile = {
t: integer;
};
/** The `Tileset` definition is the most important part among project definitions. It contains some extra informations about each integrated tileset. If you only had to parse one definition section, that would be the one. */
export declare type LDtkTilesetDef = {
export type LDtkTilesetDef = {
/** Grid-based height */
__cHei: integer;
/** Grid-based width */
@@ -565,14 +565,14 @@ export declare type LDtkTilesetDef = {
uid: integer;
};
/** In a tileset definition, user defined meta-data of a tile. */
declare type LDtkTileCustomMetadata = {
type LDtkTileCustomMetadata = {
/** */
data: string;
/** */
tileId: integer;
};
/** This object represents a custom sub rectangle in a Tileset image. */
declare type LDtkTilesetRect = {
type LDtkTilesetRect = {
/** Height in pixels */
h: integer;
/** UID of the tileset */
@@ -584,6 +584,6 @@ declare type LDtkTilesetRect = {
/** Y pixels coordinate of the top-left corner in the Tileset image */
y: integer;
};
declare type LDtkWorld = {};
type LDtkWorld = {};
export {};
//# sourceMappingURL=LDtkFormat.d.ts.map

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@ import { float, integer } from '../../model/CommonTypes';
/**
* Tiled JSON format (https://github.com/mapeditor/tiled/blob/master/docs/reference/json-map-format.rst).
*/
export declare type TiledTileMap = {
export type TiledTileMap = {
/** Hex-formatted color (#RRGGBB or #AARRGGBB) (optional) */
backgroundcolor?: string;
/** The compression level to use for tile layer data (defaults to -1, which means to use the algorithm default) */
@@ -44,7 +44,7 @@ export declare type TiledTileMap = {
/** Number of tile columns */
width: integer;
};
export declare type TiledLayer = {
export type TiledLayer = {
/** Array of {@link TiledChunk} (optional). `tilelayer` only. */
chunks?: Array<TiledChunk>;
/** `zlib`, `gzip`, `zstd` (since Tiled 1.3) or empty (default). `tilelayer` only. */
@@ -98,7 +98,7 @@ export declare type TiledLayer = {
/** Vertical layer offset in tiles. Always 0. */
y: integer;
};
export declare type TiledChunk = {
export type TiledChunk = {
/** Array of `unsigned` `integer` (GIDs) or base64-encoded data */
data: Array<integer> | string;
/** Height in tiles */
@@ -110,7 +110,7 @@ export declare type TiledChunk = {
/** Y coordinate in tiles */
y: integer;
};
export declare type TiledObject = {
export type TiledObject = {
/** The class of the object (was saved as class in 1.9, optional) */
type?: string;
/** The class of the object (used only in 1.9, optional) */
@@ -148,7 +148,7 @@ export declare type TiledObject = {
/** Y coordinate in pixels */
y: float;
};
export declare type TiledText = {
export type TiledText = {
/** Whether to use a bold font (default: `false`) */
bold: boolean;
/** Hex-formatted color (#RRGGBB or #AARRGGBB) (default: `#000000`) */
@@ -174,7 +174,7 @@ export declare type TiledText = {
/** Whether the text is wrapped within the object bounds (default: `false`) */
wrap: boolean;
};
export declare type TiledTileset = {
export type TiledTileset = {
/** Hex-formatted color (#RRGGBB or #AARRGGBB) (optional) */
backgroundcolor?: string;
/** The number of tile columns in the tileset */
@@ -226,7 +226,7 @@ export declare type TiledTileset = {
/** Array of {@link TiledWangSet} (since 1.1.5) */
wangsets?: Array<TiledWangSet>;
};
export declare type TiledGrid = {
export type TiledGrid = {
/** Cell height of tile grid */
height: integer;
/** `orthogonal` (default) or `isometric` */
@@ -234,13 +234,13 @@ export declare type TiledGrid = {
/** Cell width of tile grid */
width: integer;
};
export declare type TileOffset = {
export type TileOffset = {
/** Horizontal offset in pixels */
x: integer;
/** Vertical offset in pixels (positive is down) */
y: integer;
};
export declare type TiledTransformations = {
export type TiledTransformations = {
/** Tiles can be flipped horizontally */
hflip: boolean;
/** Tiles can be flipped vertically */
@@ -250,7 +250,7 @@ export declare type TiledTransformations = {
/** Whether untransformed tiles remain preferred, otherwise transformed tiles are used to produce more variations */
preferuntransformed: boolean;
};
export declare type TiledTileDefinition = {
export type TiledTileDefinition = {
/** Array of {@link TiledTiles} */
animation?: Array<TiledTileDefinition>;
/** The class of the object (was saved as class in 1.9, optional) */
@@ -274,13 +274,13 @@ export declare type TiledTileDefinition = {
/** Index of terrain for each corner of tile (optional) */
terrain?: Array<integer>;
};
export declare type TiledFrame = {
export type TiledFrame = {
/** Frame duration in milliseconds */
duration: integer;
/** Local tile ID representing this frame */
tileid: integer;
};
export declare type TiledTerrain = {
export type TiledTerrain = {
/** Name of terrain */
name: string;
/** Array of {@link TiledProperty} */
@@ -288,7 +288,7 @@ export declare type TiledTerrain = {
/** Local ID of tile representing terrain */
tile: integer;
};
export declare type TiledWangSet = {
export type TiledWangSet = {
/** Array of {@link TiledWangColor} */
colors: Array<TiledWangColor>;
/** Name of the Wang set */
@@ -300,7 +300,7 @@ export declare type TiledWangSet = {
/** Array of {@link TiledWangTile} */
wangtiles: Array<TiledWangTile>;
};
export declare type TiledWangColor = {
export type TiledWangColor = {
/** Hex-formatted color (#RRGGBB or #AARRGGBB) */
color: string;
/** Name of the Wang color */
@@ -312,13 +312,13 @@ export declare type TiledWangColor = {
/** Local ID of tile representing the Wang color */
tile: integer;
};
export declare type TiledWangTile = {
export type TiledWangTile = {
/** Local ID of tile */
tileid: integer;
/** Array of Wang color indexes (`uchar[8]`) */
wangid: Array<integer>;
};
export declare type TiledObjectTemplate = {
export type TiledObjectTemplate = {
/** `template` */
type: string;
/** External tileset used by the template (optional) */
@@ -326,7 +326,7 @@ export declare type TiledObjectTemplate = {
/** The object instantiated by this template */
object: Object;
};
export declare type TiledProperty = {
export type TiledProperty = {
/** Name of the property */
name: string;
/** type of the property (`string` (default), `integer`, `float`, `boolean`, `color` or `file` (since 0.16, with `color` and `file` added in 0.17)) */
@@ -334,7 +334,7 @@ export declare type TiledProperty = {
/** Value of the property */
value: string | number;
};
export declare type TiledPoint = {
export type TiledPoint = {
/** X coordinate in pixels */
x: float;
/** Y coordinate in pixels */

File diff suppressed because one or more lines are too long

View File

@@ -12,7 +12,7 @@ export declare const decodeBase64LayerData: (
pako: any,
tiledLayer: TiledLayer
) => number[];
export declare type TiledGID = {
export type TiledGID = {
id: integer;
flippedHorizontally: boolean;
flippedVertically: boolean;

View File

@@ -1 +1 @@
{"version":3,"file":"TiledTileMapLoaderHelper.d.ts","sourceRoot":"","sources":["../../../src/load/tiled/TiledTileMapLoaderHelper.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,SAAU,GAAG,cAAc,UAAU,aAgDtE,CAAC;AAEF,oBAAY,QAAQ,GAAG;IACrB,EAAE,EAAE,OAAO,CAAC;IACZ,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,kBACvB,OAAO,KACrB,QAmBF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAEpB"}
{"version":3,"file":"TiledTileMapLoaderHelper.d.ts","sourceRoot":"","sources":["../../../src/load/tiled/TiledTileMapLoaderHelper.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,SAAU,GAAG,cAAc,UAAU,aAgDtE,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,OAAO,CAAC;IACZ,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,iBAAiB,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,kBACvB,OAAO,KACrB,QAmBF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAEpB"}

View File

@@ -1,5 +1,5 @@
export declare type integer = number;
export declare type float = number;
export declare type FloatPoint = [float, float];
export declare type PolygonVertices = FloatPoint[];
export type FloatPoint = [float, float];
export type PolygonVertices = FloatPoint[];
//# sourceMappingURL=CommonTypes.d.ts.map

View File

@@ -1 +1 @@
{"version":3,"file":"CommonTypes.d.ts","sourceRoot":"","sources":["../../src/model/CommonTypes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,MAAM,OAAO,GAAG,MAAM,CAAC;AACrC,MAAM,CAAC,OAAO,MAAM,KAAK,GAAG,MAAM,CAAC;AACnC,oBAAY,UAAU,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAExC,oBAAY,eAAe,GAAG,UAAU,EAAE,CAAC"}
{"version":3,"file":"CommonTypes.d.ts","sourceRoot":"","sources":["../../src/model/CommonTypes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,MAAM,OAAO,GAAG,MAAM,CAAC;AACrC,MAAM,CAAC,OAAO,MAAM,KAAK,GAAG,MAAM,CAAC;AACnC,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAExC,MAAM,MAAM,eAAe,GAAG,UAAU,EAAE,CAAC"}

View File

@@ -65,5 +65,6 @@ export declare class TileMapManager {
levelIndex: number,
callback: (textureCache: TileTextureCache | null) => void
): void;
clearCaches(): void;
}
//# sourceMappingURL=TileMapManager.d.ts.map

View File

@@ -1 +1 @@
{"version":3,"file":"TileMapManager.d.ts","sourceRoot":"","sources":["../../src/render/TileMapManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,mBAAmB,CAAkC;;IAO7D;;;OAGG;IACH,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,MAAM,GAAG,cAAc;IAWzD;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,kBAAkB,GAAG,IAAI;IAwBrD;;;;;;;OAOG;IACH,gBAAgB,CACd,WAAW,EAAE,CACX,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,QAAQ,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,KAC9D,IAAI,EACT,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,GAAG,EACT,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,GAClD,IAAI;IAiCP;;;;;;;;OAQG;IACH,qBAAqB,CACnB,WAAW,EAAE,CACX,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,QAAQ,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,KAC9D,IAAI,EACT,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,EACpE,sBAAsB,EAAE,MAAM,EAC9B,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,KAAK,IAAI,GACxD,IAAI;CAuCR"}
{"version":3,"file":"TileMapManager.d.ts","sourceRoot":"","sources":["../../src/render/TileMapManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,aAAa,CAAiC;IACtD,OAAO,CAAC,mBAAmB,CAAkC;;IAO7D;;;OAGG;IACH,MAAM,CAAC,UAAU,CAAC,cAAc,EAAE,MAAM,GAAG,cAAc;IAWzD;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,kBAAkB,GAAG,IAAI;IAwBrD;;;;;;;OAOG;IACH,gBAAgB,CACd,WAAW,EAAE,CACX,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,QAAQ,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,KAC9D,IAAI,EACT,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,GAAG,EACT,QAAQ,EAAE,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,KAAK,IAAI,GAClD,IAAI;IAiCP;;;;;;;;OAQG;IACH,qBAAqB,CACnB,WAAW,EAAE,CACX,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,QAAQ,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,GAAG,IAAI,KAAK,IAAI,KAC9D,IAAI,EACT,UAAU,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,EACpE,sBAAsB,EAAE,MAAM,EAC9B,uBAAuB,EAAE,MAAM,EAC/B,uBAAuB,EAAE,MAAM,EAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,YAAY,EAAE,gBAAgB,GAAG,IAAI,KAAK,IAAI,GACxD,IAAI;IAwCP,WAAW,IAAI,IAAI;CAIpB"}

View File

@@ -1,9 +1,7 @@
import { TileTextureCache } from '../TileTextureCache';
import { LDtkTileMap } from '../../load/ldtk/LDtkFormat';
declare type Texture = PIXI.BaseTexture<PIXI.Resource>;
declare type TextureLoader = (
textureName: string
) => PIXI.BaseTexture<PIXI.Resource>;
type Texture = PIXI.BaseTexture<PIXI.Resource>;
type TextureLoader = (textureName: string) => PIXI.BaseTexture<PIXI.Resource>;
export declare namespace LDtkPixiHelper {
/**
* Split an atlas image into Pixi textures.

View File

@@ -1 +1 @@
{"version":3,"file":"LDtkPixiHelper.d.ts","sourceRoot":"","sources":["../../../src/render/ldtk/LDtkPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAkB,MAAM,4BAA4B,CAAC;AAGzE,aAAK,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC/C,aAAK,aAAa,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAmC9E,yBAAiB,cAAc,CAAC;IAC9B;;;;;;;;OAQG;IACH,SAAgB,UAAU,CACxB,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,OAAO,GAAG,IAAI,EAC5B,UAAU,EAAE,aAAa,GACxB,gBAAgB,GAAG,IAAI,CAoFzB;CACF"}
{"version":3,"file":"LDtkPixiHelper.d.ts","sourceRoot":"","sources":["../../../src/render/ldtk/LDtkPixiHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAkB,MAAM,4BAA4B,CAAC;AAGzE,KAAK,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC/C,KAAK,aAAa,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAmC9E,yBAAiB,cAAc,CAAC;IAC9B;;;;;;;;OAQG;IACH,SAAgB,UAAU,CACxB,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,OAAO,GAAG,IAAI,EAC5B,UAAU,EAAE,aAAa,GACxB,gBAAgB,GAAG,IAAI,CAoFzB;CACF"}

View File

@@ -2296,6 +2296,7 @@ interface VectorUnfilledRequiredBehaviorPropertyProblem {
interface ProjectBrowserHelper {
void STATIC_ExposeProjectEvents([Ref] Project project, [Ref] ArbitraryEventsWorker worker);
void STATIC_ExposeProjectObjects([Ref] Project project, [Ref] ArbitraryObjectsWorker worker);
};
interface ResourceExposer {
@@ -2884,6 +2885,10 @@ interface ArbitraryEventsWorker {
void Launch([Ref] EventsList events);
};
interface ArbitraryObjectsWorker {
void Launch([Ref] ObjectsContainer container);
};
interface EventsLeaderboardsLister {
void EventsLeaderboardsLister([Ref] Project project);
[Const, Ref] SetString GetLeaderboardIds();
@@ -2980,6 +2985,14 @@ interface ProjectResourcesCopier {
boolean preserveDirectoryStructure);
};
interface ObjectsUsingResourceCollector {
void ObjectsUsingResourceCollector([Const] DOMString resourceName);
[Const, Ref] VectorString GetObjectNames();
//Inherited from ArbitraryObjectsWorker
void Launch([Ref] ObjectsContainer container);
};
interface ResourcesInUseHelper {
void ResourcesInUseHelper();

View File

@@ -47,6 +47,8 @@
#include <GDCore/IDE/Events/EventsIdentifiersFinder.h>
#include <GDCore/IDE/Events/EventsFunctionSelfCallChecker.h>
#include <GDCore/IDE/Project/ArbitraryResourceWorker.h>
#include <GDCore/IDE/Project/ArbitraryObjectsWorker.h>
#include <GDCore/IDE/Project/ObjectsUsingResourceCollector.h>
#include <GDCore/IDE/Project/ProjectResourcesAdder.h>
#include <GDCore/IDE/Project/ProjectResourcesCopier.h>
#include <GDCore/IDE/Project/ResourcesInUseHelper.h>
@@ -574,6 +576,7 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
#define STATIC_RemoveObjectInEvents RemoveObjectInEvents
#define STATIC_ReplaceStringInEvents ReplaceStringInEvents
#define STATIC_ExposeProjectEvents ExposeProjectEvents
#define STATIC_ExposeProjectObjects ExposeProjectObjects
#define STATIC_ExposeWholeProjectResources ExposeWholeProjectResources
#define STATIC_GetBehaviorMetadata GetBehaviorMetadata

View File

@@ -1556,6 +1556,73 @@ describe('libGD.js', function () {
});
});
describe('gd.ObjectsUsingResourceCollector', function () {
it('lists objects that use the given resources', function () {
const project = gd.ProjectHelper.createNewGDJSProject();
const layout = project.insertNewLayout('Scene', 0);
const object = layout.insertNewObject(project, 'Sprite', 'MyObject', 0);
const sprite1 = new gd.Sprite();
sprite1.setImageName('Image1');
const sprite2 = new gd.Sprite();
sprite2.setImageName('Image2');
const sprite3 = new gd.Sprite();
sprite3.setImageName('Image3');
const spriteObject = gd.asSpriteConfiguration(object.getConfiguration());
const animation = new gd.Animation();
animation.setDirectionsCount(1);
animation.getDirection(0).addSprite(sprite1);
animation.getDirection(0).addSprite(sprite2);
animation.getDirection(0).addSprite(sprite1);
spriteObject.addAnimation(animation);
const object2 = project.insertNewObject(
project,
'Sprite',
'MyObject2',
0
);
const spriteObject2 = gd.asSpriteConfiguration(
object2.getConfiguration()
);
const animation2 = new gd.Animation();
animation2.setDirectionsCount(1);
animation2.getDirection(0).addSprite(sprite1);
animation2.getDirection(0).addSprite(sprite3);
animation2.getDirection(0).addSprite(sprite1);
spriteObject2.addAnimation(animation2);
{
const objectsCollector = new gd.ObjectsUsingResourceCollector('Image1');
gd.ProjectBrowserHelper.exposeProjectObjects(project, objectsCollector);
const objectNames = objectsCollector.getObjectNames().toJSArray();
objectsCollector.delete();
expect(objectNames.length).toEqual(2);
expect(objectNames).toContain('MyObject');
expect(objectNames).toContain('MyObject2');
}
{
const objectsCollector = new gd.ObjectsUsingResourceCollector('Image2');
gd.ProjectBrowserHelper.exposeProjectObjects(project, objectsCollector);
const objectNames = objectsCollector.getObjectNames().toJSArray();
objectsCollector.delete();
expect(objectNames.length).toEqual(1);
expect(objectNames).toContain('MyObject');
}
{
const objectsCollector = new gd.ObjectsUsingResourceCollector('Image3');
gd.ProjectBrowserHelper.exposeProjectObjects(project, objectsCollector);
const objectNames = objectsCollector.getObjectNames().toJSArray();
objectsCollector.delete();
expect(objectNames.length).toEqual(1);
expect(objectNames).toContain('MyObject2');
}
project.delete();
});
});
describe('gd.Behavior', function () {
it('update a not existing property', function () {
const project = gd.ProjectHelper.createNewGDJSProject();

View File

@@ -0,0 +1,6 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdArbitraryObjectsWorker {
launch(container: gdObjectsContainer): void;
delete(): void;
ptr: number;
};

View File

@@ -0,0 +1,8 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdObjectsUsingResourceCollector {
constructor(resourceName: string): void;
getObjectNames(): gdVectorString;
launch(container: gdObjectsContainer): void;
delete(): void;
ptr: number;
};

View File

@@ -1,6 +1,7 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdProjectBrowserHelper {
static exposeProjectEvents(project: gdProject, worker: gdArbitraryEventsWorker): void;
static exposeProjectObjects(project: gdProject, worker: gdArbitraryObjectsWorker): void;
delete(): void;
ptr: number;
};

View File

@@ -201,6 +201,7 @@ declare class libGDevelop {
AbstractFileSystemJS: Class<gdAbstractFileSystemJS>;
ProjectResourcesAdder: Class<gdProjectResourcesAdder>;
ArbitraryEventsWorker: Class<gdArbitraryEventsWorker>;
ArbitraryObjectsWorker: Class<gdArbitraryObjectsWorker>;
EventsLeaderboardsLister: Class<gdEventsLeaderboardsLister>;
EventsLeaderboardsRenamer: Class<gdEventsLeaderboardsRenamer>;
EventsParametersLister: Class<gdEventsParametersLister>;
@@ -214,6 +215,7 @@ declare class libGDevelop {
ResourcesMergingHelper: Class<gdResourcesMergingHelper>;
ResourcesRenamer: Class<gdResourcesRenamer>;
ProjectResourcesCopier: Class<gdProjectResourcesCopier>;
ObjectsUsingResourceCollector: Class<gdObjectsUsingResourceCollector>;
ResourcesInUseHelper: Class<gdResourcesInUseHelper>;
EditorSettings: Class<gdEditorSettings>;
Point: Class<gdPoint>;

View File

@@ -177,4 +177,9 @@ export class TileMapManager {
callback
);
}
clearCaches(): void {
this._tileMapCache = new ResourceCache<EditableTileMap>();
this._textureCacheCaches = new ResourceCache<TileTextureCache>();
}
}

View File

@@ -20,6 +20,7 @@
"algoliasearch": "3.33.0",
"axios": "^0.18.1",
"blueimp-md5": "^2.10.0",
"chokidar": "3.5.3",
"classnames": "2.2.5",
"date-fns": "2.16.1",
"element-closest": "2.0.2",
@@ -12158,7 +12159,6 @@
},
"node_modules/anymatch": {
"version": "3.1.2",
"dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
@@ -13218,7 +13218,6 @@
},
"node_modules/binary-extensions": {
"version": "2.1.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -13347,7 +13346,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
@@ -13751,7 +13749,6 @@
},
"node_modules/chokidar": {
"version": "3.5.3",
"dev": true,
"funding": [
{
"type": "individual",
@@ -17316,7 +17313,6 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -18217,7 +18213,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@@ -18412,7 +18407,6 @@
},
"node_modules/glob-parent": {
"version": "5.1.2",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
@@ -19557,7 +19551,6 @@
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"dev": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
@@ -19686,7 +19679,6 @@
},
"node_modules/is-extglob": {
"version": "2.1.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -19740,7 +19732,6 @@
},
"node_modules/is-glob": {
"version": "4.0.3",
"dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@@ -19808,7 +19799,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
@@ -25852,7 +25842,6 @@
},
"node_modules/normalize-path": {
"version": "3.0.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -26624,7 +26613,6 @@
},
"node_modules/picomatch": {
"version": "2.3.1",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@@ -30884,7 +30872,6 @@
},
"node_modules/readdirp": {
"version": "3.6.0",
"dev": true,
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
@@ -33770,7 +33757,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
@@ -44460,7 +44446,6 @@
},
"anymatch": {
"version": "3.1.2",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -45249,8 +45234,7 @@
"dev": true
},
"binary-extensions": {
"version": "2.1.0",
"dev": true
"version": "2.1.0"
},
"bl": {
"version": "4.1.0",
@@ -45358,7 +45342,6 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
@@ -45605,7 +45588,6 @@
},
"chokidar": {
"version": "3.5.3",
"dev": true,
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -48161,7 +48143,6 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
@@ -48811,7 +48792,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"optional": true
},
"function-bind": {
@@ -48933,7 +48913,6 @@
},
"glob-parent": {
"version": "5.1.2",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
@@ -49701,7 +49680,6 @@
},
"is-binary-path": {
"version": "2.1.0",
"dev": true,
"requires": {
"binary-extensions": "^2.0.0"
}
@@ -49761,8 +49739,7 @@
"version": "2.1.1"
},
"is-extglob": {
"version": "2.1.1",
"dev": true
"version": "2.1.1"
},
"is-finite": {
"version": "1.1.0",
@@ -49792,7 +49769,6 @@
},
"is-glob": {
"version": "4.0.3",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
@@ -49835,8 +49811,7 @@
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"is-number-object": {
"version": "1.0.7",
@@ -54247,8 +54222,7 @@
}
},
"normalize-path": {
"version": "3.0.0",
"dev": true
"version": "3.0.0"
},
"normalize-range": {
"version": "0.1.2",
@@ -54776,8 +54750,7 @@
"dev": true
},
"picomatch": {
"version": "2.3.1",
"dev": true
"version": "2.3.1"
},
"pify": {
"version": "4.0.1"
@@ -57558,7 +57531,6 @@
},
"readdirp": {
"version": "3.6.0",
"dev": true,
"requires": {
"picomatch": "^2.2.1"
}
@@ -59629,7 +59601,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}

View File

@@ -50,6 +50,7 @@
"algoliasearch": "3.33.0",
"axios": "^0.18.1",
"blueimp-md5": "^2.10.0",
"chokidar": "3.5.3",
"classnames": "2.2.5",
"date-fns": "2.16.1",
"element-closest": "2.0.2",

View File

@@ -315,6 +315,10 @@ export class EventsSheetComponentWithoutHandle extends React.Component<
}
}
onResourceExternallyChanged = resourceInfo => {
if (this._eventsTree) this._eventsTree.forceEventsUpdate();
};
updateToolbar() {
if (!this.props.setToolbar) return;
@@ -1991,6 +1995,7 @@ export class EventsSheetComponentWithoutHandle extends React.Component<
export type EventsSheetInterface = {|
updateToolbar: () => void,
onResourceExternallyChanged: ({| identifier: string |}) => void,
|};
// EventsSheet is a wrapper so that the component can use multiple
@@ -1998,12 +2003,17 @@ export type EventsSheetInterface = {|
const EventsSheet = (props, ref) => {
React.useImperativeHandle(ref, () => ({
updateToolbar,
onResourceExternallyChanged,
}));
const component = React.useRef<?EventsSheetComponentWithoutHandle>(null);
const updateToolbar = () => {
if (component.current) component.current.updateToolbar();
};
const onResourceExternallyChanged = resourceInfo => {
if (component.current)
component.current.onResourceExternallyChanged(resourceInfo);
};
const authenticatedUser = React.useContext(AuthenticatedUserContext);
const preferences = React.useContext(PreferencesContext);

View File

@@ -1055,6 +1055,12 @@ export default class InstancesEditor extends Component<Props> {
pauseSceneRendering = () => {
if (this.nextFrame) cancelAnimationFrame(this.nextFrame);
this._renderingPaused = true;
// Deactivate interactions when the scene is paused.
// Useful when the scene is paused to reload textures. The event system
// might try to check if pointer is over a PIXI object using the texture
// of the object. If there is no texture, it will crash.
// The PIXI.EventSystem is not based on the PIXI.Ticker.
this.instancesRenderer.getPixiContainer().eventMode = 'none';
stopPIXITicker();
};
@@ -1062,6 +1068,7 @@ export default class InstancesEditor extends Component<Props> {
restartSceneRendering = () => {
this._renderingPaused = false;
this._renderScene();
this.instancesRenderer.getPixiContainer().eventMode = 'auto';
startPIXITicker();
};

View File

@@ -199,8 +199,6 @@ export default function makeExtensionsLoader({
jsExtensions
.filter(({ name }) => !filterExamples || !name.includes('Example'))
.map(({ name, extensionModule, objectsRenderingServiceModules }) => {
// Load any editor for objects, if we have somewhere where
// to register them.
if (
objectsEditorService &&
extensionModule.registerEditorConfigurations
@@ -210,25 +208,23 @@ export default function makeExtensionsLoader({
);
}
// Register modules for ObjectsRenderingService
if (objectsRenderingService && objectsRenderingServiceModules) {
for (let requirePath in objectsRenderingServiceModules) {
objectsRenderingService.registerModule(
requirePath,
objectsRenderingServiceModules[requirePath]
if (objectsRenderingService) {
if (objectsRenderingServiceModules) {
for (const requirePath in objectsRenderingServiceModules) {
objectsRenderingService.registerModule(
requirePath,
objectsRenderingServiceModules[requirePath]
);
}
}
if (extensionModule.registerInstanceRenderers) {
extensionModule.registerInstanceRenderers(
objectsRenderingService
);
}
}
// Load any renderer for objects, if we have somewhere where
// to register them.
if (
objectsRenderingService &&
extensionModule.registerInstanceRenderers
) {
extensionModule.registerInstanceRenderers(
objectsRenderingService
);
if (extensionModule.registerClearCache) {
extensionModule.registerClearCache(objectsRenderingService);
}
}
return {

View File

@@ -56,47 +56,45 @@ module.exports = function makeExtensionsLoader(
};
}
if (extensionModule) {
// Load any editor for objects, if we have somewhere where
// to register them.
if (
objectsEditorService &&
extensionModule.registerEditorConfigurations
) {
extensionModule.registerEditorConfigurations(
objectsEditorService
);
}
if (!extensionModule) {
return {
extensionModulePath,
result: {
error: true,
message:
'Unknown error. Please check for any syntax error or error that would prevent it from being run.',
},
};
}
// Load any renderer for objects, if we have somewhere where
// to register them.
if (
objectsRenderingService &&
extensionModule.registerInstanceRenderers
) {
if (
objectsEditorService &&
extensionModule.registerEditorConfigurations
) {
extensionModule.registerEditorConfigurations(
objectsEditorService
);
}
if (objectsRenderingService) {
if (extensionModule.registerInstanceRenderers) {
extensionModule.registerInstanceRenderers(
objectsRenderingService
);
}
return {
extensionModulePath,
result: loadExtension(
_,
gd,
gd.JsPlatform.get(),
extensionModule
),
};
if (extensionModule.registerClearCache) {
extensionModule.registerClearCache(objectsRenderingService);
}
}
return {
extensionModulePath,
result: {
error: true,
message:
'Unknown error. Please check for any syntax error or error that would prevent it from being run.',
},
result: loadExtension(
_,
gd,
gd.JsPlatform.get(),
extensionModule
),
};
})
);

View File

@@ -48,6 +48,10 @@ export class ExternalEventsEditorContainer extends React.Component<
return this.props.isActive || nextProps.isActive;
}
onResourceExternallyChanged = (resourceInfo: {| identifier: string |}) => {
if (this.editor) this.editor.onResourceExternallyChanged(resourceInfo);
};
getProject(): ?gdProject {
return this.props.project;
}

View File

@@ -76,6 +76,13 @@ export class ExternalLayoutEditorContainer extends React.Component<
}
}
onResourceExternallyChanged(resourceInfo: {| identifier: string |}) {
const { editor } = this;
if (editor) {
editor.onResourceExternallyChanged(resourceInfo);
}
}
updateToolbar() {
if (this.editor) this.editor.updateToolbar();
}

View File

@@ -0,0 +1,37 @@
import * as React from 'react';
import ResourcesLoader from '../ResourcesLoader';
const useResourcesWatcher = (getStorageProvider, fileMetadata, editorTabs) => {
const informEditorsResourceExternallyChanged = React.useCallback(
(resourceInfo: {| identifier: string |}) => {
ResourcesLoader.burstAllUrlsCache();
editorTabs.editors.forEach(editorTab => {
if (
editorTab.editorRef &&
editorTab.editorRef.editor &&
editorTab.editorRef.editor.onResourceExternallyChanged
) {
// Each editor container has an accessible editor property.
// $FlowFixMe[not-a-function]
editorTab.editorRef.editor.onResourceExternallyChanged(resourceInfo);
}
});
},
[editorTabs]
);
React.useEffect(
() => {
const storageProvider = getStorageProvider();
if (fileMetadata && storageProvider.setupResourcesWatcher) {
const unsubscribe = storageProvider.setupResourcesWatcher(
fileMetadata,
informEditorsResourceExternallyChanged
);
return unsubscribe;
}
},
[fileMetadata, informEditorsResourceExternallyChanged, getStorageProvider]
);
};
export default useResourcesWatcher;

View File

@@ -180,7 +180,8 @@ import newNameGenerator from '../Utils/NewNameGenerator';
import { addDefaultLightToAllLayers } from '../ProjectCreation/CreateProject';
import useEditorTabsStateSaving from './EditorTabs/UseEditorTabsStateSaving';
import { type PrivateGameTemplateListingData } from '../Utils/GDevelopServices/Shop';
import PixiResourcesLoader from '../ObjectsRendering/PixiResourcesLoader';
import useResourcesWatcher from './ResourcesWatcher';
const GD_STARTUP_TIMES = global.GD_STARTUP_TIMES || [];
const gd: libGDevelop = global.gd;
@@ -498,6 +499,11 @@ const MainFrame = (props: Props) => {
ensureResourcesAreFetched,
renderResourceFetcherDialog,
} = useResourceFetcher({ resourceFetcher });
useResourcesWatcher(
getStorageProvider,
currentFileMetadata,
state.editorTabs
);
/**
* This reference is useful to get the current opened project,
@@ -898,7 +904,7 @@ const MainFrame = (props: Props) => {
// the URL to a resource with a name in the old project is not re-used
// for another resource with the same name in the new project.
ResourcesLoader.burstAllUrlsCache();
// TODO: Pixi cache should also be burst
PixiResourcesLoader.burstCache();
const state = await setState(state => ({
...state,

View File

@@ -157,6 +157,10 @@ const ObjectsRenderingService = {
this.renderers3D[objectType] = renderer;
},
renderersCacheClearingMethods: [],
registerClearCache: function(clearCache: (project: gdProject) => void) {
this.renderersCacheClearingMethods.push(clearCache);
},
/**
* Register a module that can be then required using `requireModule`.
* This is necessary for the web-app, as all files must be bundled.

View File

@@ -10,13 +10,13 @@ import { loadFontFace } from '../Utils/FontFaceLoader';
import { checkIfCredentialsRequired } from '../Utils/CrossOrigin';
const gd: libGDevelop = global.gd;
const loadedBitmapFonts = {};
const loadedFontFamilies = {};
const loadedTextures = {};
let loadedBitmapFonts = {};
let loadedFontFamilies = {};
let loadedTextures = {};
const invalidTexture = PIXI.Texture.from('res/error48.png');
const loadedThreeTextures = {};
const loadedThreeMaterials = {};
const loadedOrLoading3DModelPromises: {
let loadedThreeTextures = {};
let loadedThreeMaterials = {};
let loadedOrLoading3DModelPromises: {
[resourceName: string]: Promise<THREE.THREE_ADDONS.GLTF>,
} = {};
@@ -150,6 +150,49 @@ const traverseToRemoveMetalnessFromMeshes = (
* This internally uses ResourcesLoader to get the URL of the resources.
*/
export default class PixiResourcesLoader {
static burstCache() {
loadedBitmapFonts = {};
loadedFontFamilies = {};
loadedTextures = {};
loadedThreeTextures = {};
loadedThreeMaterials = {};
loadedOrLoading3DModelPromises = {};
}
static async reloadTextureForResource(
project: gdProject,
resourceName: string
) {
const loadedTexture = loadedTextures[resourceName];
if (loadedTexture && loadedTexture.textureCacheIds) {
await PIXI.Assets.unload(loadedTexture.textureCacheIds);
}
await PixiResourcesLoader.loadTextures(project, [resourceName], () => {});
if (loadedOrLoading3DModelPromises[resourceName]) {
delete loadedOrLoading3DModelPromises[resourceName];
}
if (loadedFontFamilies[resourceName]) {
delete loadedFontFamilies[resourceName];
}
if (loadedBitmapFonts[resourceName]) {
delete loadedBitmapFonts[resourceName];
}
if (loadedThreeTextures[resourceName]) {
loadedThreeTextures[resourceName].dispose();
delete loadedThreeTextures[resourceName];
}
const matchingMaterials = Object.keys(loadedThreeMaterials).filter(key =>
key.startsWith(resourceName)
);
if (matchingMaterials.length > 0) {
matchingMaterials.forEach(key => {
loadedThreeMaterials[key].dispose();
delete loadedThreeMaterials[key];
});
}
}
/**
* (Re)load the PIXI texture represented by the given resources.
*/

View File

@@ -0,0 +1,60 @@
// @flow
import optionalRequire from '../../Utils/OptionalRequire';
import { type FileMetadata } from '..';
import debounce from 'lodash/debounce';
import wrap from 'lodash/wrap';
import memoize from 'lodash/memoize';
const fileWatcher = optionalRequire('chokidar');
const path = optionalRequire('path');
export const setupResourcesWatcher =
fileWatcher && path
? (
fileMetadata: FileMetadata,
callback: ({| identifier: string |}) => void
) => {
// We can't just debounce the whole callback, it has to be done file-wise,
// otherwise we would miss all the debounced calls but the last one.
// See https://stackoverflow.com/questions/28787436/debounce-a-function-with-argument
const debouncedCallback = wrap(
memoize(() =>
debounce(
filePath => {
const relativePath = path
.relative(folderPath, filePath)
.replace(/\\/g, '/');
callback({ identifier: relativePath });
},
200,
{ leading: false, trailing: true }
)
),
(getMemoizedFunc, obj) => getMemoizedFunc(obj)(obj)
);
const folderPath = path.dirname(fileMetadata.fileIdentifier);
const gameFile = path.basename(fileMetadata.fileIdentifier);
const autosaveFile = gameFile + '.autosave';
const watcher = fileWatcher
.watch(folderPath, {
ignored: [
`**/.DS_Store`,
path.join(folderPath, gameFile),
path.join(folderPath, autosaveFile),
],
awaitWriteFinish: {
stabilityThreshold: 250,
pollInterval: 100,
},
})
.on(
'change',
// TODO: Is it safe to let it like that since the OS could for some reason
// do never-ending operations on the folder or its children, making the debounce
// never ending.
debouncedCallback
);
return () => watcher.unwatch(folderPath);
}
: undefined;

View File

@@ -36,6 +36,7 @@ import {
type ShowAlertFunction,
type ShowConfirmFunction,
} from '../../UI/Alert/AlertContext';
import { setupResourcesWatcher } from './LocalFileResourcesWatcher';
/**
* Use the Electron APIs to provide access to the native
@@ -55,6 +56,7 @@ export default ({
},
getProjectLocation: getProjectLocation,
renderNewProjectSaveAsLocationChooser: renderNewProjectSaveAsLocationChooser,
setupResourcesWatcher,
createOperations: () => ({
onOpenWithPicker,
onOpen,

View File

@@ -193,4 +193,9 @@ export type StorageProvider = {|
createResourceOperations?: ({|
authenticatedUser: AuthenticatedUser,
|}) => ResourcesActionsMenuBuilder,
/** Resources external changes */
setupResourcesWatcher?: (
fileMetadata: FileMetadata,
callback: ({| identifier: string |}) => void
) => () => void,
|};

View File

@@ -63,19 +63,7 @@ const ResourcePropertiesEditor = React.forwardRef<
},
ref
) => {
const _forceUpdate = useForceUpdate();
const resourcePreviewRef = React.useRef<?ResourcePreview>(null);
const forceUpdate = React.useCallback(
() => {
_forceUpdate();
if (resourcePreviewRef.current) {
resourcePreviewRef.current.forceUpdate();
}
},
[_forceUpdate]
);
const forceUpdate = useForceUpdate();
React.useImperativeHandle(ref, () => ({ forceUpdate }));
const chooseResourcePath = React.useCallback(
@@ -183,7 +171,6 @@ const ResourcePropertiesEditor = React.forwardRef<
return (
<ResourcePreview
ref={resourcePreviewRef}
resourceName={resources[0].getName()}
resourcesLoader={resourcesLoader}
project={project}

View File

@@ -205,6 +205,13 @@ export default class ResourcesEditor extends React.Component<Props, State> {
);
};
onResourceExternallyChanged = (resourceInfo: {| identifier: string |}) => {
if (this._propertiesEditor) {
this._propertiesEditor.forceUpdate();
}
this.refreshResourcesList();
};
render() {
const {
project,

View File

@@ -1,7 +1,6 @@
// @flow
import * as React from 'react';
import ResourcesLoader from '../../ResourcesLoader';
import { type ResourceKind } from '../ResourceSource';
import ImagePreview, { isProjectImageResourceSmooth } from './ImagePreview';
import GenericIconPreview from './GenericIconPreview';
import FontDownload from '@material-ui/icons/FontDownload';
@@ -16,80 +15,50 @@ type Props = {|
onSize?: (number, number) => void,
|};
type State = {|
resourceKind: ?ResourceKind,
|};
/**
* Display the right preview for any given resource of a project
*/
export default class ResourcePreview extends React.PureComponent<Props, State> {
state = this._loadFrom(this.props);
const ResourcePreview = (props: Props) => {
const { project, resourceName } = props;
const resourcesManager = project.getResourcesManager();
const resourceKind = resourcesManager.hasResource(resourceName)
? resourcesManager.getResource(resourceName).getKind()
: null;
// To be updated, see https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops.
UNSAFE_componentWillReceiveProps(newProps: Props) {
if (
newProps.resourceName !== this.props.resourceName ||
newProps.project !== this.props.project
) {
this.setState(this._loadFrom(newProps));
}
switch (resourceKind) {
case 'image':
return (
<ImagePreview
resourceName={resourceName}
imageResourceSource={props.resourcesLoader.getResourceFullUrl(
project,
resourceName,
{}
)}
isImageResourceSmooth={isProjectImageResourceSmooth(
project,
resourceName
)}
onSize={props.onSize}
/>
);
case 'audio':
return <GenericIconPreview renderIcon={props => <Music {...props} />} />;
case 'json':
case 'tilemap':
case 'tileset':
case 'model3D':
return <GenericIconPreview renderIcon={props => <File {...props} />} />;
case 'video':
return <GenericIconPreview renderIcon={props => <Video {...props} />} />;
case 'font':
case 'bitmapFont':
return (
<GenericIconPreview renderIcon={props => <FontDownload {...props} />} />
);
default:
return null;
}
};
_loadFrom(props: Props): State {
const { project, resourceName } = props;
const resourcesManager = project.getResourcesManager();
const resourceKind = resourcesManager.hasResource(resourceName)
? resourcesManager.getResource(resourceName).getKind()
: null;
return {
resourceKind,
};
}
render() {
const { resourceKind } = this.state;
switch (resourceKind) {
case 'image':
return (
<ImagePreview
resourceName={this.props.resourceName}
imageResourceSource={this.props.resourcesLoader.getResourceFullUrl(
this.props.project,
this.props.resourceName,
{}
)}
isImageResourceSmooth={isProjectImageResourceSmooth(
this.props.project,
this.props.resourceName
)}
onSize={this.props.onSize}
/>
);
case 'audio':
return (
<GenericIconPreview renderIcon={props => <Music {...props} />} />
);
case 'json':
case 'tilemap':
case 'tileset':
case 'model3D':
return <GenericIconPreview renderIcon={props => <File {...props} />} />;
case 'video':
return (
<GenericIconPreview renderIcon={props => <Video {...props} />} />
);
case 'font':
case 'bitmapFont':
return (
<GenericIconPreview
renderIcon={props => <FontDownload {...props} />}
/>
);
default:
return null;
}
}
}
export default ResourcePreview;

View File

@@ -135,6 +135,7 @@ export type SceneEditorsDisplayInterface = {|
getLastContextMenuSceneCoordinates: () => [number, number],
getViewPosition: () => ?ViewPosition,
|},
startSceneRendering: (start: boolean) => void,
instancesHandlers: {|
getSelectionAABB: () => Rectangle,
addInstances: (

View File

@@ -151,6 +151,14 @@ const MosaicEditorsDisplay = React.forwardRef<
return editorMosaicRef.current.getOpenedEditorNames().includes(editorId);
}, []);
const startSceneRendering = React.useCallback((start: boolean) => {
const editor = editorRef.current;
if (!editor) return;
if (start) editor.restartSceneRendering();
else editor.pauseSceneRendering();
}, []);
React.useImperativeHandle(ref, () => {
const { current: editor } = editorRef;
return {
@@ -163,6 +171,7 @@ const MosaicEditorsDisplay = React.forwardRef<
openNewObjectDialog,
toggleEditorView,
isEditorVisible,
startSceneRendering,
viewControls: {
zoomBy: editor ? editor.zoomBy : noop,
setZoomFactor: editor ? editor.setZoomFactor : noop,

View File

@@ -137,6 +137,14 @@ const SwipeableDrawerEditorsDisplay = React.forwardRef<
[selectedEditorId, drawerOpeningState]
);
const startSceneRendering = React.useCallback((start: boolean) => {
const editor = editorRef.current;
if (!editor) return;
if (start) editor.restartSceneRendering();
else editor.pauseSceneRendering();
}, []);
React.useImperativeHandle(ref, () => {
const { current: editor } = editorRef;
@@ -150,6 +158,7 @@ const SwipeableDrawerEditorsDisplay = React.forwardRef<
openNewObjectDialog,
toggleEditorView: halfOpenOrCloseDrawerOnEditor,
isEditorVisible,
startSceneRendering,
viewControls: {
zoomBy: editor ? editor.zoomBy : noop,
setZoomFactor: editor ? editor.setZoomFactor : noop,

View File

@@ -62,6 +62,7 @@ import MosaicEditorsDisplay from './MosaicEditorsDisplay';
import SwipeableDrawerEditorsDisplay from './SwipeableDrawerEditorsDisplay';
import { type SceneEditorsDisplayInterface } from './EditorsDisplay.flow';
import newNameGenerator from '../Utils/NewNameGenerator';
import ObjectsRenderingService from '../ObjectsRendering/ObjectsRenderingService';
const gd: libGDevelop = global.gd;
@@ -206,6 +207,49 @@ export default class SceneEditor extends React.Component<Props, State> {
return this.state.instancesEditorSettings;
}
onResourceExternallyChanged = async (resourceInfo: {|
identifier: string,
|}) => {
const { project } = this.props;
const resourceName = project
.getResourcesManager()
.getResourceNameWithFile(resourceInfo.identifier);
if (resourceName) {
const { editorDisplay } = this;
if (!editorDisplay) return;
try {
// When reloading textures, there can be a short time during which
// the existing texture is removed but the InstancesEditor tries to use it
// through the RenderedInstance's, triggering crashes. So the scene rendering
// is paused during this period.
editorDisplay.startSceneRendering(false);
await PixiResourcesLoader.reloadTextureForResource(
project,
resourceName
);
editorDisplay.forceUpdateObjectsList();
const objectsCollector = new gd.ObjectsUsingResourceCollector(
resourceName
);
// $FlowIgnore - Flow does not know ObjectsUsingResourceCollector inherits from ArbitraryObjectsWorker
gd.ProjectBrowserHelper.exposeProjectObjects(project, objectsCollector);
const objectNames = objectsCollector.getObjectNames().toJSArray();
objectsCollector.delete();
ObjectsRenderingService.renderersCacheClearingMethods.forEach(clear =>
clear(project)
);
objectNames.forEach(objectName => {
editorDisplay.instancesHandlers.resetInstanceRenderersFor(objectName);
});
} finally {
editorDisplay.startSceneRendering(true);
}
}
};
updateToolbar = () => {
const { editorDisplay } = this;
if (!editorDisplay) return;

View File

@@ -3,6 +3,9 @@ import * as PIXI from 'pixi.js-legacy';
// PIXI has a ticker that is used by PIXI InteractionManager, and which
// frequently check if interaction happened. We may want to disable it
// when it's useless to do these interaction checks to save CPU usage.
// TODO: We might not need this anymore since PIXI v7 dropped the use of
// InteractionManager in favor of EventSystem that does not seem
// to use a ticker.
/**
* Stop the PIXI Ticker used to monitor interactions