diff --git a/Engine/Binaries/ThirdParty/AppLocalDependencies/WinDbg.tps b/Engine/Binaries/ThirdParty/AppLocalDependencies/WinDbg.tps
new file mode 100644
index 000000000000..5da1716a34d6
--- /dev/null
+++ b/Engine/Binaries/ThirdParty/AppLocalDependencies/WinDbg.tps
@@ -0,0 +1,13 @@
+
+
+ Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1 (WinDbg)
+ Engine/Binaries/ThirdParty/AppLocalDependencies/Win64/DbgHelp/dbghelp.dll
+ Used for retrieving a callstack from a minidump.
+ https://www.microsoft.com/en-us/download/details.aspx?id=3138
+
+ Licensees
+ Git
+ P4
+
+ N/A
+
\ No newline at end of file
diff --git a/Engine/Build/Android/Java/aar-imports-ant.txt b/Engine/Build/Android/Java/aar-imports-ant.txt
new file mode 100644
index 000000000000..93e43560a672
--- /dev/null
+++ b/Engine/Build/Android/Java/aar-imports-ant.txt
@@ -0,0 +1,6 @@
+repositories $(ANDROID_HOME)/extras
+repositories $(ENGINEDIR)/Source/ThirdParty/Android/extras
+com.google.android.gms,play-services-auth,11.0.4
+com.google.android.gms,play-services-games,11.0.4
+com.google.android.gms,play-services-nearby,11.0.4
+com.google.android.gms,play-services-plus,11.0.4
diff --git a/Engine/Build/Android/Java/aar-imports.txt b/Engine/Build/Android/Java/aar-imports.txt
index 93e43560a672..dd637110b367 100644
--- a/Engine/Build/Android/Java/aar-imports.txt
+++ b/Engine/Build/Android/Java/aar-imports.txt
@@ -1,6 +1,6 @@
repositories $(ANDROID_HOME)/extras
repositories $(ENGINEDIR)/Source/ThirdParty/Android/extras
-com.google.android.gms,play-services-auth,11.0.4
-com.google.android.gms,play-services-games,11.0.4
-com.google.android.gms,play-services-nearby,11.0.4
-com.google.android.gms,play-services-plus,11.0.4
+com.google.android.gms,play-services-auth,11.8.0
+com.google.android.gms,play-services-games,11.8.0
+com.google.android.gms,play-services-nearby,11.8.0
+com.google.android.gms,play-services-plus,11.8.0
diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java.template
similarity index 89%
rename from Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java
rename to Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java.template
index 45c55f37147f..c970f873e60d 100644
--- a/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java
+++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/GameActivity.java.template
@@ -45,6 +45,7 @@ import android.text.TextWatcher;
import android.view.inputmethod.EditorInfo;
import android.content.ClipboardManager;
import android.content.ClipData;
+import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@@ -58,6 +59,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.FeatureInfo;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
+import android.provider.Settings;
import android.provider.Settings.Secure;
import android.content.pm.PackageInfo;
@@ -153,24 +155,35 @@ import android.content.BroadcastReceiver;
public class GameActivity extends NativeActivity implements SurfaceHolder.Callback2,
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
- SensorEventListener
+ SensorEventListener,
+ ComponentCallbacks2
{
+ private boolean bAllowIMU = true;
private SensorManager sensorManager;
private Sensor accelerometer;
private Sensor magnetometer;
private Sensor gyroscope;
+ static boolean first_acceleration_sample = true;
+ static final float SampleDecayRate = 0.85f;
private final float[] rotationMatrix = new float[9];
private final float[] orientationAngles = new float[3];
- static float[] last_accelerometer = new float[]{0, 0, 0};
- static float[] last_magnetometer = new float[]{0, 0, 0};
- // Buffered, historical, motion data.
- static float[] last_tilt = new float[]{0, 0, 0};
- static float[] last_gravity = new float[]{0, 0, 0};
+ static float[] current_accelerometer = new float[]{0, 0, 0};
+ static float[] current_gyroscope = new float[]{0, 0, 0};
+ static float[] current_magnetometer = new float[]{0, 0, 0};
+
+ static float[] filtered_gravity = new float[]{0, 0, 0};
+ static float[] last_gravity = new float[]{0, 0, 0};
+ static float[] last_tilt = new float[]{0, 0, 0};
+
+ // active motion state to return to application on request
+ boolean bSensorDataUpdated = false;
+ float[] current_tilt = new float[]{0, 0, 0};
+ static float[] current_rotation_rate = new float[]{0, 0, 0};
+ static float[] current_gravity = new float[]{0, 0, 0};
+ static float[] current_acceleration = new float[]{0, 0, 0};
- static boolean first_acceleration_sample = true;
- static final float SampleDecayRate = 0.85f;
public static Logger Log = new Logger("UE4");
// From cpufeatures.h AndroidCpuFamily enum
@@ -181,6 +194,15 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
private static final int ANDROID_CPU_FAMILY_ARM64 = 4;
private static final int ANDROID_CPU_FAMILY_X86_64 = 5;
private static final int ANDROID_CPU_FAMILY_MIPS64 = 6;
+
+ // For GetNetworkConnectionType
+ private static final int CONNECTION_TYPE_NONE = 0;
+ private static final int CONNECTION_TYPE_AIRPLANEMODE = 1;
+ private static final int CONNECTION_TYPE_ETHERNET = 2;
+ private static final int CONNECTION_TYPE_CELL = 3;
+ private static final int CONNECTION_TYPE_WIFI = 4;
+ private static final int CONNECTION_TYPE_WIMAX = 5;
+ private static final int CONNECTION_TYPE_BLUETOOTH = 6;
public static final int DOWNLOAD_ACTIVITY_ID = 80001; // so we can identify the activity later
public static final int DOWNLOAD_NO_RETURN_CODE = 0; // we didn't get a return code - will need to log and debug as this shouldn't happen
@@ -195,9 +217,11 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
public static enum VirtualKeyboardCommand { VK_CMD_NONE, VK_CMD_SHOW, VK_CMD_HIDE };
public static VirtualKeyboardCommand lastVirtualKeyboardCommand = VirtualKeyboardCommand.VK_CMD_NONE;
public static final int lastVirtualKeyboardCommandDelay = 200;
+ public static final int checkLastVirtualKeyboardCommandDelay = 500;
static GameActivity _activity;
static Bundle _bundle;
+ static Bundle _extrasBundle;
protected Dialog mSplashDialog;
private int noActionAnimID = -1;
@@ -422,18 +446,23 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
gyroscope = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
+
// create splashscreen dialog (if launched by SplashActivity)
- Bundle intentBundle = getIntent().getExtras();
- if (intentBundle != null)
+ _extrasBundle = getIntent().getExtras();
+ if (_extrasBundle != null)
{
- ShouldHideUI = intentBundle.getString("ShouldHideUI") != null;
- if (intentBundle.getString("UseSplashScreen") != null)
+ ShouldHideUI = _extrasBundle.getString("ShouldHideUI") != null;
+ if (_extrasBundle.getString("UseSplashScreen") != null)
{
try {
// try to get the splash theme (can't use R.style.UE4SplashTheme since we don't know the package name until runtime)
int SplashThemeId = getResources().getIdentifier("UE4SplashTheme", "style", getPackageName());
mSplashDialog = new Dialog(this, SplashThemeId);
mSplashDialog.setCancelable(false);
+
+ // Setting NOT_FOCUSABLE prevents the splash dialog from kicking some devices out of immersive mode.
+ mSplashDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+
if (ShouldHideUI)
{
View decorView = mSplashDialog.getWindow().getDecorView();
@@ -762,6 +791,12 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
Log.debug( "bUseExternalFilesDir not found. Leaving as " + UseExternalFilesDir);
}
+ if(bundle.containsKey("com.epicgames.ue4.GameActivity.bAllowIMU"))
+ {
+ bAllowIMU = bundle.getBoolean("com.epicgames.ue4.GameActivity.bAllowIMU");
+ Log.debug( "AllowIMU set to " + bAllowIMU);
+ }
+
//$${gameActivityReadMetadataAdditions}$$
}
catch (NameNotFoundException e)
@@ -775,7 +810,7 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
Log.debug("APK path: " + getPackageResourcePath());
Log.debug("OBB in APK: " + (PackageDataInsideApkValue==1));
- nativeSetGlobalActivity(UseExternalFilesDir, PackageDataInsideApkValue==1, getPackageResourcePath());
+ nativeSetGlobalActivity(UseExternalFilesDir, getFilesDir().getPath(), getExternalFilesDir(null).getPath(), PackageDataInsideApkValue==1, getPackageResourcePath());
// tell the engine if this is a portrait app
nativeSetWindowInfo(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT, DepthBufferPreference);
@@ -784,10 +819,14 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
// note: this may need to be Locale.getDefault().getLanguage()
String Language = java.util.Locale.getDefault().toString();
+ boolean bDebuggerAttached = android.os.Debug.isDebuggerConnected();
+ nativeSetAndroidStartupState(bDebuggerAttached);
+
Log.debug( "Android version is " + android.os.Build.VERSION.RELEASE );
Log.debug( "Android manufacturer is " + android.os.Build.MANUFACTURER );
Log.debug( "Android model is " + android.os.Build.MODEL );
Log.debug( "OS language is set to " + Language );
+ Log.debug( "Debugger attached is " + bDebuggerAttached );
nativeSetAndroidVersionInformation( android.os.Build.VERSION.RELEASE, android.os.Build.MANUFACTURER, android.os.Build.MODEL, Language );
@@ -1188,9 +1227,23 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
return;
}
- sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
- sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_GAME);
- sensorManager.registerListener(this, gyroscope, SensorManager.SENSOR_DELAY_GAME);
+ if (bAllowIMU)
+ {
+ Log.debug("Registering sensor listeners");
+ if (accelerometer != null)
+ {
+ sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
+ }
+ if (magnetometer != null)
+ {
+ sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_GAME);
+ }
+ if (gyroscope != null)
+ {
+ sensorManager.registerListener(this, gyroscope, SensorManager.SENSOR_DELAY_GAME);
+ }
+ }
+
// invalidate window cache
nativeSetWindowInfo(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT, DepthBufferPreference);
@@ -1258,7 +1311,12 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
protected void onPause()
{
super.onPause();
- sensorManager.unregisterListener(this);
+
+ if (bAllowIMU)
+ {
+ Log.debug("Unregistering sensor listeners");
+ sensorManager.unregisterListener(this);
+ }
// hide virtual keyboard before going into the background
if( bKeyboardShowing )
@@ -1297,127 +1355,99 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
@Override
public void onSensorChanged(SensorEvent event)
{
- float[] current_accelerometer = new float[]{0, 0, 0};
- float[] current_gyroscope = new float[]{0, 0, 0};
- float[] current_magnetometer = new float[]{0, 0, 0};
- int current_accelerometer_sample_count = 0;
- int current_gyroscope_sample_count = 0;
- int current_magnetometer_sample_count = 0;
-
- if (accelerometer != null && magnetometer != null)
+ if (bAllowIMU && accelerometer != null && magnetometer != null)
{
+ boolean bUpdate = false;
+ boolean bGyroUpdate = false;
+
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
{
- System.arraycopy(event.values, 0, current_accelerometer, 0, current_accelerometer.length);
- ++current_accelerometer_sample_count;
+ System.arraycopy(event.values, 0, current_accelerometer, 0, 3);
+ bUpdate = true;
+
+ // We use a low-pass filter to synthesize the gravity vector.
+ if (!first_acceleration_sample)
+ {
+ filtered_gravity[0] = last_gravity[0] * SampleDecayRate + current_accelerometer[0]*(1.0f - SampleDecayRate);
+ filtered_gravity[1] = last_gravity[1] * SampleDecayRate + current_accelerometer[1]*(1.0f - SampleDecayRate);
+ filtered_gravity[2] = last_gravity[2] * SampleDecayRate + current_accelerometer[2]*(1.0f - SampleDecayRate);
+ }
+ first_acceleration_sample = false;
+ last_gravity = filtered_gravity;
}
else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
{
- System.arraycopy(event.values, 0, current_magnetometer, 0, current_magnetometer.length);
- ++current_magnetometer_sample_count;
+ System.arraycopy(event.values, 0, current_magnetometer, 0, 3);
+ bUpdate = true;
}
else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE)
{
- System.arraycopy(event.values, 0, current_gyroscope, 0, current_gyroscope.length);
- ++current_gyroscope_sample_count;
- }
-
- if (current_accelerometer_sample_count > 0)
- {
- // Do simple average of the samples we just got.
- for(int i = 0; i < current_accelerometer.length; i++)
- current_accelerometer[i] /= (float)current_accelerometer_sample_count;
- last_accelerometer = current_accelerometer;
- }
- else
- {
- current_accelerometer = last_accelerometer;
- }
-
- if (current_gyroscope_sample_count > 0)
- {
- // Do simple average of the samples we just got.
- for(int i = 0; i < current_gyroscope.length; i++)
- current_gyroscope[i] /= (float)current_gyroscope_sample_count;
- }
-
- if (current_magnetometer_sample_count > 0)
- {
- // Do simple average of the samples we just got.
- for(int i = 0; i < current_magnetometer.length; i++)
- current_magnetometer[i] /= (float)current_magnetometer_sample_count;
- last_magnetometer = current_magnetometer;
- }
- else
- {
- current_magnetometer = last_magnetometer;
+ System.arraycopy(event.values, 0, current_gyroscope, 0, 3);
+ bUpdate = true;
+ bGyroUpdate = true;
}
// If we have motion samples we generate the single event.
- if (current_accelerometer_sample_count > 0 || current_gyroscope_sample_count > 0 || current_magnetometer_sample_count > 0)
+ if (bUpdate)
{
- // The data we compose the motion event from.
- float[] current_tilt = new float[]{0, 0, 0};
- float[] current_rotation_rate = new float[]{0, 0, 0};
- float[] current_gravity = new float[]{0, 0, 0};
- float[] current_acceleration = new float[]{0, 0, 0};
-
-
-
- // We use a low-pass filter to synthesize the gravity
- // vector.
-
- if (!first_acceleration_sample)
- {
- current_gravity[0] = last_gravity[0] * SampleDecayRate + current_accelerometer[0]*(1.0f - SampleDecayRate);
- current_gravity[1] = last_gravity[1] * SampleDecayRate + current_accelerometer[1]*(1.0f - SampleDecayRate);
- current_gravity[2] = last_gravity[2] * SampleDecayRate + current_accelerometer[2]*(1.0f - SampleDecayRate);
- }
- first_acceleration_sample = false;
-
// get the rotation matrix value, the convert those to Euler angle rotation values
- updateOrientationAngles(current_accelerometer, current_magnetometer);
+ sensorManager.getRotationMatrix(rotationMatrix, null, current_accelerometer, current_magnetometer);
+ sensorManager.getOrientation(rotationMatrix, orientationAngles);
- current_tilt = new float[]{orientationAngles[1], orientationAngles[2], orientationAngles[0]};
-
- // And take out the gravity from the accel to get
- // the linear acceleration.
- for (int i = 0; i < current_acceleration.length; ++i)
- current_acceleration[i] = current_accelerometer[i] - current_gravity[i];
-
- if (current_gyroscope_sample_count > 0)
+ // protect against request from other thread
+ synchronized(this)
{
- // The rotation rate is the what the gyroscope gives us.
- current_rotation_rate = current_gyroscope;
- }
- else if (null == gyroscope)
- {
- // If we don't have a gyroscope at all we need to calc a rotation
- // rate from our calculated tilt and a delta.
- for (int index = 0; index < current_rotation_rate.length; ++index)
- current_rotation_rate[index] = current_tilt[index] - last_tilt[index];
+ // remember gravity
+ current_gravity = filtered_gravity;
+
+ // fix up the tilt mapping to proper coordinate frame
+ current_tilt[0] = orientationAngles[1];
+ current_tilt[1] = orientationAngles[2];
+ current_tilt[2] = orientationAngles[0];
+
+ // And take out the gravity from the accel to get the linear acceleration.
+ current_acceleration[0] = current_accelerometer[0] - current_gravity[0];
+ current_acceleration[1] = current_accelerometer[1] - current_gravity[1];
+ current_acceleration[2] = current_accelerometer[2] - current_gravity[2];
+
+ // Figure out the rotation rate
+ if (bGyroUpdate)
+ {
+ // The rotation rate is the what the gyroscope gives us.
+ current_rotation_rate = current_gyroscope;
+ }
+ else if (null == gyroscope)
+ {
+ // If we don't have a gyroscope at all we need to calc a rotation rate from delta from previous tilt.
+ current_rotation_rate[0] = current_tilt[0] - last_tilt[0];
+ current_rotation_rate[1] = current_tilt[1] - last_tilt[1];
+ current_rotation_rate[2] = current_tilt[2] - last_tilt[2];
+ }
+ last_tilt = current_tilt;
}
- // Finally record the motion event with all the data.
-
- nativeHandleSensorEvents(current_tilt, current_rotation_rate, current_gravity, current_acceleration);
-
- // Update history values.
- last_tilt = current_tilt;
- last_gravity = current_gravity;
+ // flag new sensor data ready
+ bSensorDataUpdated = true;
}
}
}
-
- public void updateOrientationAngles(float[] accelerometerReading, float[] magnetometerReading)
+ public void AndroidThunkJava_PushSensorEvents()
{
-
- sensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading);
-
- sensorManager.getOrientation(rotationMatrix, orientationAngles);
+ if (bAllowIMU)
+ {
+ // protect against other thread updating the values
+ synchronized(this)
+ {
+ if (bSensorDataUpdated)
+ {
+ nativeHandleSensorEvents(current_tilt, current_rotation_rate, current_gravity, current_acceleration);
+ bSensorDataUpdated = false;
+ }
+ }
+ }
}
-
+
@Override
public void onNewIntent(Intent newIntent)
{
@@ -1426,6 +1456,46 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
//$${gameActivityOnNewIntentAdditions}$$
}
+ public void onTrimMemory(int level)
+ {
+ // Determine which lifecycle or system event was raised.
+ switch (level) {
+ // user interface is in background, release UI memory
+ case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
+ Log.debug("==============> GameActive.onTrimMemory(TRIM_MEMORY_UI_HIDDEN) called!");
+ break;
+
+ // app is running but getting low on memory
+ case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
+ Log.debug("==============> GameActive.onTrimMemory(TRIM_MEMORY_RUNNING_MODERATE) called!");
+ break;
+ case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
+ Log.debug("==============> GameActive.onTrimMemory(TRIM_MEMORY_RUNNING_LOW) called!");
+ break;
+ case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
+ // system will begin killing background processes
+ Log.debug("==============> GameActive.onTrimMemory(TRIM_MEMORY_RUNNING_CRITICAL) called!");
+ break;
+
+ // app is on LRU list (background), release what you can
+ case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
+ Log.debug("==============> GameActive.onTrimMemory(TRIM_MEMORY_BACKGROUND) called!");
+ break;
+ case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+ Log.debug("==============> GameActive.onTrimMemory(TRIM_MEMORY_MODERATE) called!");
+ break;
+ case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+ // this process up first to kill for more memory!
+ Log.debug("==============> GameActive.onTrimMemory(TRIM_MEMORY_COMPLETE) called!");
+ break;
+
+ // unrecognized level; generic low memory situation
+ default:
+ Log.debug("==============> GameActive.onTrimMemory(" + level + ") called!");
+ break;
+ }
+ }
+
@Override
public void onStop()
{
@@ -1740,8 +1810,6 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
//TYPE: disable text suggestion
newVirtualKeyboardInputType |= InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
- //TYPE: disable autocorrect
- newVirtualKeyboardInputType &= ~InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
//TYPE: set input type flags
newVirtualKeyboardInput.setInputType(newVirtualKeyboardInputType);
@@ -1794,6 +1862,8 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
nativeVirtualKeyboardVisible(true);
bKeyboardShowing = true;
+
+ CheckKeyboardDisplayed();
}
}
break;
@@ -1822,6 +1892,25 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
lastVirtualKeyboardCommand = VirtualKeyboardCommand.VK_CMD_NONE;
}
+ // timer to check if the onGlobalLayout callback was correctly called when displaying the virtual keyboard
+ private void CheckKeyboardDisplayed()
+ {
+ virtualKeyboardHandler.postDelayed(new Runnable()
+ {
+ public void run()
+ {
+ synchronized(this)
+ {
+ if(bKeyboardShowing && newVirtualKeyboardInput.getY() < 0)
+ {
+ //couldn't show the VK input. Force layout refresh
+ mainView.requestLayout();
+ }
+ }
+ }
+ }, checkLastVirtualKeyboardCommandDelay);
+ }
+
public void AndroidThunkJava_LaunchURL(String URL)
{
Log.debug("[JAVA} AndroidThunkJava_LaunchURL: URL = " + URL);
@@ -1866,6 +1955,32 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
return null;
}
+ public void AndroidThunkJava_ShareURL(String URL, String Description, String Prompt, int LocationX, int LocationY)
+ {
+ Log.debug("[JAVA} AndroidThunkJava_ShareURL: URL = " + URL);
+
+ if (!URL.contains("://"))
+ {
+ URL = "http://" + URL;
+ Log.debug("[JAVA} AndroidThunkJava_ShareURL: corrected URL = " + URL);
+ }
+
+ try
+ {
+ Intent SendIntent = new Intent(Intent.ACTION_SEND);
+ SendIntent.setType("text/plain");
+ SendIntent.putExtra(Intent.EXTRA_SUBJECT, Description);
+ SendIntent.putExtra(Intent.EXTRA_TEXT, URL);
+
+ Log.debug("[JAVA} AndroidThunkJava_ShareURL: Sharing URL");
+ startActivity(Intent.createChooser(SendIntent, Prompt));
+ }
+ catch (Exception e)
+ {
+ Log.debug("[JAVA} AndroidThunkJava_ShareURL: Failed with exception " + e.getMessage());
+ }
+ }
+
public void AndroidThunkJava_ResetAchievements()
{
/* Disable so don't need GET_ACCOUNTS - we don't need this
@@ -2688,17 +2803,67 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
return false;
}
- public boolean AndroidThunkJava_HasActiveWiFiConnection()
+ @SuppressWarnings("deprecation")
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+ public static boolean isAirplaneModeOn(Context context)
{
- ConnectivityManager cm = (ConnectivityManager)this.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)
+ {
+ return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0;
+ }
+ return Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+ }
+
+ public String getConnectionType()
+ {
+ if (isAirplaneModeOn(getApplicationContext()))
+ {
+ return "AirplaneMode";
+ }
+
+ ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
-
- boolean isConnected = (activeNetwork != null && activeNetwork.isConnectedOrConnecting());
+
+ boolean isConnected = (activeNetwork != null && activeNetwork.isAvailable() && activeNetwork.isConnectedOrConnecting());
if (isConnected)
{
- return (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI);
+ int connType = activeNetwork.getType();
+ switch (connType)
+ {
+ case ConnectivityManager.TYPE_WIFI: return "WiFi";
+ case ConnectivityManager.TYPE_BLUETOOTH: return "Bluetooth";
+ case ConnectivityManager.TYPE_ETHERNET: return "Ethernet";
+ case ConnectivityManager.TYPE_WIMAX: return "WiMAX";
+ }
+ return "Cell";
}
- return false;
+ return "None";
+ }
+
+ public int AndroidThunkJava_GetNetworkConnectionType()
+ {
+ if (isAirplaneModeOn(getApplicationContext()))
+ {
+ return CONNECTION_TYPE_AIRPLANEMODE;
+ }
+
+ ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
+
+ boolean isConnected = (activeNetwork != null && activeNetwork.isAvailable() && activeNetwork.isConnectedOrConnecting());
+ if (isConnected)
+ {
+ int connType = activeNetwork.getType();
+ switch (connType)
+ {
+ case ConnectivityManager.TYPE_WIFI: return CONNECTION_TYPE_WIFI;
+ case ConnectivityManager.TYPE_BLUETOOTH: return CONNECTION_TYPE_BLUETOOTH;
+ case ConnectivityManager.TYPE_ETHERNET: return CONNECTION_TYPE_ETHERNET;
+ case ConnectivityManager.TYPE_WIMAX: return CONNECTION_TYPE_WIMAX;
+ }
+ return CONNECTION_TYPE_CELL;
+ }
+ return CONNECTION_TYPE_NONE;
}
public boolean AndroidThunkJava_HasMetaDataKey(String key)
@@ -2829,6 +2994,41 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
return _bundle.getString(key);
}
+ public boolean AndroidThunkJava_HasIntentExtrasKey(String key)
+ {
+ if (_extrasBundle == null || key == null)
+ {
+ return false;
+ }
+ return _extrasBundle.containsKey(key);
+ }
+
+ public boolean AndroidThunkJava_GetIntentExtrasBoolean(String key)
+ {
+ if (_extrasBundle == null || key == null)
+ {
+ return false;
+ }
+ return _extrasBundle.getBoolean(key);
+ }
+
+ public int AndroidThunkJava_GetIntentExtrasInt(String key)
+ {
+ if (_extrasBundle == null || key == null)
+ {
+ return 0;
+ }
+ return _extrasBundle.getInt(key);
+ }
+
+ public String AndroidThunkJava_GetIntentExtrasString(String key)
+ {
+ if (_extrasBundle == null || key == null)
+ {
+ return null;
+ }
+ return _extrasBundle.getString(key);
+ }
public void AndroidThunkJava_SetSustainedPerformanceMode(final boolean bEnable)
{
@@ -3193,6 +3393,22 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
return false;
}
+
+ public boolean AndroidThunkJava_LaunchPackage(String packageName, String extraKey, String extraValue)
+ {
+ Intent launchIntent = getPackageManager().getLaunchIntentForPackage(packageName);
+ if (launchIntent != null)
+ {
+ if (extraKey != "")
+ {
+ launchIntent.putExtra(extraKey, extraValue);
+ }
+ startActivity(launchIntent);
+ System.exit(0);
+ }
+ return false;
+ }
+
public void AndroidThunkJava_RestartApplication()
{
Context context = getApplicationContext();
@@ -3229,7 +3445,8 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
public native boolean nativeSupportsNEON();
public native boolean nativeIsShippingBuild();
- public native void nativeSetGlobalActivity(boolean bUseExternalFilesDir, boolean bOBBInAPK, String APKPath);
+ public native void nativeSetAndroidStartupState(boolean bDebuggerAttached);
+ public native void nativeSetGlobalActivity(boolean bUseExternalFilesDir, String internalFilePath, String externalFilePath, boolean bOBBInAPK, String APKPath);
public native void nativeSetWindowInfo(boolean bIsPortrait, int DepthBufferPreference);
public native void nativeSetObbInfo(String ProjectName, String PackageName, int Version, int PatchVersion, String AppType);
public native void nativeSetAndroidVersionInformation( String AndroidVersion, String PhoneMake, String PhoneModel, String OSLanguage );
@@ -3266,4 +3483,3 @@ public class GameActivity extends NativeActivity implements SurfaceHolder.Callba
private static ClipboardManager clipboardManager;
}
-
diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java
index 31ab4c0cf36c..3c08b8b16c94 100644
--- a/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java
+++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/GooglePlayStoreHelper.java
@@ -19,6 +19,7 @@ import com.android.vending.billing.util.Base64;
import com.android.vending.billing.IInAppBillingService;
import com.android.vending.billing.util.Purchase;
import java.util.ArrayList;
+import java.util.List;
import org.json.JSONException;
import org.json.JSONObject;
@@ -50,6 +51,9 @@ public class GooglePlayStoreHelper implements StoreHelper
public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST";
public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN";
+ // Max number of offers to query at once (see getSkuDetails in IInAppbillingServer.aidl)
+ public static final int QueryPurchaseMaxCount = 20;
+
// Item types
public static final String ITEM_TYPE_INAPP = "inapp";
@@ -73,6 +77,22 @@ public class GooglePlayStoreHelper implements StoreHelper
private final int UndefinedFailureResponse = -1;
+ private class GooglePlayProductDescription
+ {
+ // Product offer id
+ public String id;
+ // Product friendly name
+ public String title;
+ // Product description
+ public String description;
+ // Currency friendly string
+ public String price;
+ // Raw price in currency units
+ public Float priceRaw;
+ // Local currency code
+ public String currencyCode;
+ }
+
public interface PurchaseLaunchCallback
{
void launchForResult(PendingIntent pendingIntent, int requestCode);
@@ -88,13 +108,13 @@ public class GooglePlayStoreHelper implements StoreHelper
gameActivity = InGameActivity;
productKey = InProductKey;
-
+
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
gameActivity.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
}
-
+
///////////////////////////////////////////////////////
// The StoreHelper interfaces implementation for Google Play Store.
@@ -113,87 +133,129 @@ public class GooglePlayStoreHelper implements StoreHelper
public boolean QueryInAppPurchases(String[] InProductIDs)
{
Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases");
- ArrayList skuList = new ArrayList ();
-
- for (String productId : InProductIDs)
+
+ if (InProductIDs.length > 0)
{
- Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Querying " + productId);
- skuList.add(productId);
- }
+ ArrayList skuList = new ArrayList(InProductIDs.length);
- Bundle querySkus = new Bundle();
- querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuList);
-
- try
- {
- Bundle skuDetails = mService.getSkuDetails(3, gameActivity.getPackageName(), ITEM_TYPE_INAPP, querySkus);
-
- int response = skuDetails.getInt(RESPONSE_CODE);
- Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Response " + response + " Bundle:" + skuDetails.toString());
- if (response == BILLING_RESPONSE_RESULT_OK)
+ for (String productId : InProductIDs)
{
- ArrayList productIds = new ArrayList();
- ArrayList titles = new ArrayList();
- ArrayList descriptions = new ArrayList();
- ArrayList prices = new ArrayList();
- ArrayList pricesRaw = new ArrayList();
- ArrayList currencyCodes = new ArrayList();
+ Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Querying " + productId);
+ skuList.add(productId);
+ }
- ArrayList responseList = skuDetails.getStringArrayList(RESPONSE_GET_SKU_DETAILS_LIST);
- for (String thisResponse : responseList)
+ ArrayList productIds = new ArrayList();
+ ArrayList titles = new ArrayList();
+ ArrayList descriptions = new ArrayList();
+ ArrayList prices = new ArrayList();
+ ArrayList pricesRaw = new ArrayList();
+ ArrayList currencyCodes = new ArrayList();
+
+ while (skuList.size() > 0)
+ {
+ Log.debug("[GooglePlayStoreHelper] - NumSkus: " + skuList.size());
+ int numSkus = Math.min(QueryPurchaseMaxCount, skuList.size());
+ Log.debug("[GooglePlayStoreHelper] - Grabbing from 0 to " + numSkus);
+ List skuSubList = skuList.subList(0, numSkus);
+ ArrayList realSubList = new ArrayList(skuSubList);
+ ArrayList productDescriptions = new ArrayList();
+
+ int response = QueryInAppPurchasesInternal(realSubList, productDescriptions);
+ if (response == BILLING_RESPONSE_RESULT_OK)
{
- JSONObject object = new JSONObject(thisResponse);
-
- String productId = object.getString("productId");
- productIds.add(productId);
- Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Parsing details for: " + productId);
-
- String title = object.getString("title");
- titles.add(title);
- Log.debug("[GooglePlayStoreHelper] - title: " + title);
+ for (GooglePlayProductDescription product : productDescriptions)
+ {
+ productIds.add(product.id);
+ Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Parsing details for: " + product.id);
- String description = object.getString("description");
- descriptions.add(description);
- Log.debug("[GooglePlayStoreHelper] - description: " + description);
+ titles.add(product.title);
+ Log.debug("[GooglePlayStoreHelper] - title: " + product.title);
- String price = object.getString("price");
- prices.add(price);
- Log.debug("[GooglePlayStoreHelper] - price: " + price);
+ descriptions.add(product.description);
+ Log.debug("[GooglePlayStoreHelper] - description: " + product.description);
- double priceRaw = object.getDouble("price_amount_micros") / 1000000.0;
- pricesRaw.add((float)priceRaw);
- Log.debug("[GooglePlayStoreHelper] - price_amount_micros: " + priceRaw);
+ prices.add(product.price);
+ Log.debug("[GooglePlayStoreHelper] - price: " + product.price);
- String currencyCode = object.getString("price_currency_code");
- currencyCodes.add(currencyCode);
- Log.debug("[GooglePlayStoreHelper] - price_currency_code: " + currencyCode);
+ pricesRaw.add(product.priceRaw);
+ Log.debug("[GooglePlayStoreHelper] - price_amount_micros: " + product.priceRaw);
+
+ currencyCodes.add(product.currencyCode);
+ Log.debug("[GooglePlayStoreHelper] - price_currency_code: " + product.currencyCode);
+ }
+ }
+ else
+ {
+ Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Failed with: " + response);
+ // If anything fails right now, stop immediately, not sure how to reconcile partial success/failure
+ nativeQueryComplete(response, null, null, null, null, null, null);
+ return false;
}
- float[] pricesRawPrimitive = new float[pricesRaw.size()];
- for (int i = 0; i < pricesRaw.size(); i++)
- {
- pricesRawPrimitive[i] = pricesRaw.get(i);
- }
+ skuSubList.clear();
+ }
- Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases " + productIds.size() + " items - Success!");
- nativeQueryComplete(response, productIds.toArray(new String[productIds.size()]), titles.toArray(new String[titles.size()]), descriptions.toArray(new String[descriptions.size()]), prices.toArray(new String[prices.size()]), pricesRawPrimitive, currencyCodes.toArray(new String[currencyCodes.size()]));
- Log.debug("[GooglePlayStoreHelper] - nativeQueryComplete done!");
- }
- else
+ float[] pricesRawPrimitive = new float[pricesRaw.size()];
+ for (int i = 0; i < pricesRaw.size(); i++)
{
- Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Failed!");
- nativeQueryComplete(response, null, null, null, null, null, null);
+ pricesRawPrimitive[i] = pricesRaw.get(i);
}
+
+ Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases " + productIds.size() + " items - Success!");
+ nativeQueryComplete(BILLING_RESPONSE_RESULT_OK, productIds.toArray(new String[productIds.size()]), titles.toArray(new String[titles.size()]), descriptions.toArray(new String[descriptions.size()]), prices.toArray(new String[prices.size()]), pricesRawPrimitive, currencyCodes.toArray(new String[currencyCodes.size()]));
+ Log.debug("[GooglePlayStoreHelper] - nativeQueryComplete done!");
}
- catch(Exception e)
+ else
{
- Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Failed! " + e.getMessage());
+ // nothing to query
+ Log.debug("[GooglePlayStoreHelper] - no products given to query");
nativeQueryComplete(UndefinedFailureResponse, null, null, null, null, null, null);
}
return true;
}
-
+
+ public int QueryInAppPurchasesInternal(ArrayList skuList, ArrayList outProducts)
+ {
+ Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchasesInternal");
+
+ Bundle querySkus = new Bundle();
+ querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuList);
+
+ int response = UndefinedFailureResponse;
+ try
+ {
+ Bundle skuDetails = mService.getSkuDetails(3, gameActivity.getPackageName(), ITEM_TYPE_INAPP, querySkus);
+
+ response = skuDetails.getInt(RESPONSE_CODE);
+ Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchases - Response " + response + " Bundle:" + skuDetails.toString());
+ if (response == BILLING_RESPONSE_RESULT_OK)
+ {
+ ArrayList responseList = skuDetails.getStringArrayList(RESPONSE_GET_SKU_DETAILS_LIST);
+ for (String thisResponse : responseList)
+ {
+ JSONObject object = new JSONObject(thisResponse);
+
+ GooglePlayProductDescription newDescription = new GooglePlayProductDescription();
+ newDescription.id = object.getString("productId");
+ newDescription.title = object.getString("title");
+ newDescription.description = object.getString("description");
+ newDescription.price = object.getString("price");
+ double priceRaw = object.getDouble("price_amount_micros") / 1000000.0;
+ newDescription.priceRaw = (float)priceRaw;
+ newDescription.currencyCode = object.getString("price_currency_code");
+ outProducts.add(newDescription);
+ }
+ }
+ }
+ catch(Exception e)
+ {
+ Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryInAppPurchasesInternal - Failed! " + e.getMessage());
+ }
+
+ return response;
+ }
+
/**
* Start the purchase flow for a particular sku
*/
@@ -215,7 +277,7 @@ public class GooglePlayStoreHelper implements StoreHelper
{
Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::BeginPurchase - v7 VR purchase" + ProductID);
buyIntentBundle = mService.getBuyIntentExtraParams(7, gameActivity.getPackageName(), ProductID, ITEM_TYPE_INAPP, devPayload, bundle);
- }
+ }
else
{
Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::BeginPurchase - v3 IAB purchase:" + ProductID);
@@ -275,8 +337,8 @@ public class GooglePlayStoreHelper implements StoreHelper
ArrayList ownedSkus = new ArrayList();
ArrayList purchaseDataList = new ArrayList();
ArrayList signatureList = new ArrayList();
-
- // On first pass the continuation token should be null.
+
+ // On first pass the continuation token should be null.
// This will allow us to gather large sets of purchased items recursively
int responseCode = GatherOwnedPurchaseData(ownedSkus, purchaseDataList, signatureList, null);
if (responseCode == BILLING_RESPONSE_RESULT_OK)
@@ -315,7 +377,7 @@ public class GooglePlayStoreHelper implements StoreHelper
boolean bTryToConsume = false;
int consumeResponse = 0;
-
+
// This is assuming that all purchases should be consumed. Consuming a purchase that is meant to be a one-time purchase makes it so the
// user is able to buy it again. Also, it makes it so the purchase will not be able to be restored again in the future.
@@ -385,8 +447,8 @@ public class GooglePlayStoreHelper implements StoreHelper
ArrayList ownedSkus = new ArrayList();
ArrayList purchaseDataList = new ArrayList();
ArrayList signatureList = new ArrayList();
-
- // On first pass the continuation token should be null.
+
+ // On first pass the continuation token should be null.
// This will allow us to gather large sets of purchased items recursively
int responseCode = GatherOwnedPurchaseData(ownedSkus, purchaseDataList, signatureList, null);
if (responseCode == BILLING_RESPONSE_RESULT_OK)
@@ -408,7 +470,7 @@ public class GooglePlayStoreHelper implements StoreHelper
String receipt = Base64.encode(purchase.getOriginalJson().getBytes());
receipts.add(receipt);
- }
+ }
catch (JSONException e)
{
Log.debug("[GooglePlayStoreHelper] - GooglePlayStoreHelper::QueryExistingPurchases - Failed to parse receipt! " + e.getMessage());
@@ -482,13 +544,13 @@ public class GooglePlayStoreHelper implements StoreHelper
mService = IInAppBillingService.Stub.asInterface(service);
bIsIapSetup = true;
- try
+ try
{
Log.debug("Checking for in-app billing 3 support.");
// check for in-app billing v3 support
int response = mService.isBillingSupported(3, gameActivity.getPackageName(), ITEM_TYPE_INAPP);
- if (response != BILLING_RESPONSE_RESULT_OK)
+ if (response != BILLING_RESPONSE_RESULT_OK)
{
Log.debug("In-app billing version 3 NOT supported for " + gameActivity.getPackageName() + " error " + response);
}
@@ -505,10 +567,10 @@ public class GooglePlayStoreHelper implements StoreHelper
}
};
-
+
///////////////////////////////////////////////////////
// Game Activity/Context driven methods we need to listen for.
-
+
/**
* On Destory we should unbind our IInAppBillingService service
*/
@@ -521,7 +583,7 @@ public class GooglePlayStoreHelper implements StoreHelper
gameActivity.unbindService(mServiceConn);
}
}
-
+
/**
* Route taken by the Purchase workflow. We listen for our purchaseIntentIdentifier request code and
* handle the response accordingly
@@ -532,7 +594,7 @@ public class GooglePlayStoreHelper implements StoreHelper
if (requestCode == purchaseIntentIdentifier)
{
- if (data == null)
+ if (data == null)
{
Log.debug("Null data in purchase activity result.");
nativePurchaseComplete(UndefinedFailureResponse, "", "", "", "");
@@ -612,10 +674,10 @@ public class GooglePlayStoreHelper implements StoreHelper
return false;
}
-
+
///////////////////////////////////////////////////////
// Internal helper functions that deal assist with various IAB related events
-
+
/**
* Create a UE4 specific unique string that will be used to verify purchases are legit.
*/
@@ -623,7 +685,7 @@ public class GooglePlayStoreHelper implements StoreHelper
{
return "ue4." + ProductId;
}
-
+
/**
* Check the returned payload matches one for the product we are buying.
*/
@@ -635,7 +697,7 @@ public class GooglePlayStoreHelper implements StoreHelper
return ExistingPayload.equals(GeneratedPayload);
}
-
+
/**
* Get a text tranlation of the Response Codes returned by google play.
*/
@@ -666,7 +728,7 @@ public class GooglePlayStoreHelper implements StoreHelper
return "Unknown Server Response Code";
}
}
-
+
/**
* Recursive functionality to gather all of the purchases owned by a user.
* if the user owns a lot of products then we need to getPurchases again with a continuationToken
diff --git a/Engine/Build/Android/Java/src/com/epicgames/ue4/MediaPlayer14.java b/Engine/Build/Android/Java/src/com/epicgames/ue4/MediaPlayer14.java
index 88748004613b..2197df78ddff 100644
--- a/Engine/Build/Android/Java/src/com/epicgames/ue4/MediaPlayer14.java
+++ b/Engine/Build/Android/Java/src/com/epicgames/ue4/MediaPlayer14.java
@@ -563,6 +563,11 @@ public class MediaPlayer14
public void reset()
{
+ synchronized(this)
+ {
+ Prepared = false;
+ Completed = false;
+ }
if (null != mOESTextureRenderer)
{
while (WaitOnBitmapRender) ;
diff --git a/Engine/Build/Android/Java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java b/Engine/Build/Android/Java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
index 17832fb3d81a..d427193adbca 100644
--- a/Engine/Build/Android/Java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
+++ b/Engine/Build/Android/Java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
@@ -204,11 +204,7 @@ public class DownloadNotification implements IDownloaderClient {
mLabel = applicationLabel;
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- mActiveDownloadBuilder = new V4CustomNotificationBuilder(ctx);
- } else {
- mActiveDownloadBuilder = new NotificationCompat.Builder(ctx);
- }
+ mActiveDownloadBuilder = new NotificationCompat.Builder(ctx);
mBuilder = new NotificationCompat.Builder(ctx);
// Set Notification category and priorities to something that makes sense for a long
diff --git a/Engine/Build/Android/Java/src/com/google/android/vending/expansion/downloader/impl/V4CustomNotificationBuilder.java b/Engine/Build/Android/Java/src/com/google/android/vending/expansion/downloader/impl/V4CustomNotificationBuilder.java
deleted file mode 100644
index 42057a082a47..000000000000
--- a/Engine/Build/Android/Java/src/com/google/android/vending/expansion/downloader/impl/V4CustomNotificationBuilder.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.android.vending.expansion.downloader.R;
-import com.google.android.vending.expansion.downloader.Helpers;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.support.v4.app.NotificationCompat;
-import android.view.View;
-import android.widget.RemoteViews;
-
-/**
- * This class wraps NotificationCompat to give us similar progress functionality on Donut-Honeycomb.
- */
-public class V4CustomNotificationBuilder extends NotificationCompat.Builder {
-
- public V4CustomNotificationBuilder(Context context) {
- super(context);
- }
-
- @Override
- public NotificationCompat.Builder setProgress(int max, int progress, boolean indeterminate) {
- mTotalBytes = max;
- mCurrentBytes = progress;
- return super.setProgress(max, progress, indeterminate);
- }
-
- @Override
- public NotificationCompat.Builder setContentInfo(CharSequence info) {
- mContentInfo = info;
- return super.setContentInfo(info);
- }
-
- int mTotalBytes = -1;
- int mCurrentBytes = -1;
- int mIcon;
- CharSequence mContentInfo = "";
-
- @Override
- public Notification build() {
- if (android.os.Build.VERSION.SDK_INT > 10) {
- // only matters for Honeycomb
- setOnlyAlertOnce(true);
- }
-
- // Build the RemoteView object
- RemoteViews expandedView = new RemoteViews(
- mContext.getPackageName(),
- R.layout.status_bar_ongoing_event_progress_bar);
-
- expandedView.setTextViewText(R.id.title, mContentTitle);
- // look at strings
- expandedView.setViewVisibility(R.id.description, View.VISIBLE);
- expandedView.setTextViewText(R.id.description,
- Helpers.getDownloadProgressString(this.mCurrentBytes, mTotalBytes));
- expandedView.setViewVisibility(R.id.progress_bar_frame, View.VISIBLE);
- expandedView.setProgressBar(R.id.progress_bar,
- (int) (mTotalBytes >> 8),
- (int) (mCurrentBytes >> 8),
- mTotalBytes <= 0);
- expandedView.setViewVisibility(R.id.time_remaining, View.VISIBLE);
- expandedView.setTextViewText(
- R.id.time_remaining,
- mContentInfo);
- expandedView.setTextViewText(R.id.progress_text,
- Helpers.getDownloadProgressPercent(mCurrentBytes, mTotalBytes));
- expandedView.setImageViewResource(R.id.appIcon, mIcon);
-
- Notification n = super.build();
- n.contentView = expandedView;
- return n;
- }
-}
diff --git a/Engine/Build/BatchFiles/Mac/SetupMono.sh b/Engine/Build/BatchFiles/Mac/SetupMono.sh
index 74d8cdf0f1de..c1fcdb69edf5 100755
--- a/Engine/Build/BatchFiles/Mac/SetupMono.sh
+++ b/Engine/Build/BatchFiles/Mac/SetupMono.sh
@@ -6,13 +6,27 @@ sh FixDependencyFiles.sh
IS_MONO_INSTALLED=0
MONO_VERSION_PATH=`which mono` || true
+
+# if we can't find mono path, try one last hail mary of a standard install location
+if [ "$MONO_VERSION_PATH" == "" ] || [ ! -f $MONO_VERSION_PATH ]; then
+ MONO_VERSION_PATH="/Library/Frameworks/Mono.framework/Versions/Current/Commands/mono"
+ # if it's found, then add it to the path
+ if [ ! $MONO_VERSION_PATH == "" ] && [ -f $MONO_VERSION_PATH ]; then
+ echo "Found mono via known Mono.framework path"
+ export PATH=/Library/Frameworks/Mono.framework/Versions/Current/Commands:$PATH
+ fi
+fi
+
if [ ! $MONO_VERSION_PATH == "" ] && [ -f $MONO_VERSION_PATH ]; then
# If Mono is installed, check if it's 4.0.2 or higher
MONO_VERSION_PREFIX="Mono JIT compiler version "
MONO_VERSION_PREFIX_LEN=${#MONO_VERSION_PREFIX}
MONO_VERSION=`"${MONO_VERSION_PATH}" --version |grep "$MONO_VERSION_PREFIX"`
+ echo "Running installed mono, version: " ${MONO_VERSION}
MONO_VERSION=(`echo ${MONO_VERSION:MONO_VERSION_PREFIX_LEN} |tr '.' ' '`)
- if [ ${MONO_VERSION[0]} -ge 4 ]; then
+ if [ ${MONO_VERSION[0]} -ge 5 ]; then # Allow any Mono 5.x and up
+ IS_MONO_INSTALLED=1
+ elif [ ${MONO_VERSION[0]} -eq 4 ]; then
if [ ${MONO_VERSION[1]} -eq 0 ] && [ ${MONO_VERSION[2]} -ge 2 ]; then
IS_MONO_INSTALLED=1
elif [ ${MONO_VERSION[1]} -gt 0 ] && [ ${MONO_VERSION[1]} -lt 6 ]; then # Mono 4.6 has issues on macOS 10.12
diff --git a/Engine/Build/BuildFarm/PostpExtensions.pl b/Engine/Build/BuildFarm/PostpExtensions.pl
index 3f3c6015f482..fff3b3a34506 100644
--- a/Engine/Build/BuildFarm/PostpExtensions.pl
+++ b/Engine/Build/BuildFarm/PostpExtensions.pl
@@ -145,12 +145,12 @@ unshift @::gMatchers, (
{
id => "clErrorMultiline",
pattern => q{([^(]+)(\([\d,]+\))? ?: (fatal )?error [a-zA-Z]+[\d]+},
- action => q{incValue("errors"); my ($file_only) = ($1 =~ /([^\\\\]+)$/); diagnostic($file_only || $1, "error", 0, forwardWhile("^( |^([^(]+)\\\\([\\\\d,]+\\\\) ?: note)"))},
+ action => q{my $line = logLine($::gCurrentLine); $line =~ /^( *)/; my $indent = ' ' x length($1); incValue("errors"); my ($file_only) = ($1 =~ /([^\\\\]+)$/); diagnostic($file_only || $1, "error", 0, forwardWhile("^$indent "))},
},
{
id => "clWarningMultiline",
pattern => q{([^(]+)(\([\d,]+\))? ?: warning[ :]},
- action => q{incValue("warnings"); my ($file_only) = ($1 =~ /([^\\\\]+)$/); diagnostic($file_only || $1, "warning", 0, forwardWhile("^( |^([^(]+)\\\\([\\\\d,]+\\\\) ?: note)")) },
+ action => q{my $line = logLine($::gCurrentLine); $line =~ /^( *)/; my $indent = ' ' x length($1); incValue("warnings"); my ($file_only) = ($1 =~ /([^\\\\]+)$/); diagnostic($file_only || $1, "warning", 0, forwardWhile("^$indent "))},
},
{
id => "clangError",
diff --git a/Engine/Build/Commit.gitdeps.xml b/Engine/Build/Commit.gitdeps.xml
index 8c731bc4a8a6..951cd4d4d22c 100644
--- a/Engine/Build/Commit.gitdeps.xml
+++ b/Engine/Build/Commit.gitdeps.xml
@@ -5,10 +5,11 @@
-
-
-
-
+
+
+
+
+
@@ -28,7 +29,9 @@
-
+
+
+
@@ -54,8 +57,8 @@
-
-
+
+
@@ -168,7 +171,9 @@
+
+
@@ -2136,7 +2141,7 @@
-
+
@@ -2399,159 +2404,159 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3381,12 +3386,12 @@
-
+
-
-
+
+
-
+
@@ -3415,10 +3420,10 @@
-
+
-
-
+
+
@@ -3616,7 +3621,7 @@
-
+
@@ -5856,6 +5861,9 @@
+
+
+
@@ -6799,7 +6807,7 @@
-
+
@@ -7164,6 +7172,8 @@
+
+
@@ -7183,8 +7193,10 @@
+
+
@@ -7221,7 +7233,7 @@
-
+
@@ -7499,6 +7511,8 @@
+
+
@@ -7544,13 +7558,13 @@
-
-
+
+
-
-
-
+
+
+
@@ -7716,6 +7730,7 @@
+
@@ -7723,6 +7738,7 @@
+
@@ -7758,7 +7774,9 @@
-
+
+
+
@@ -15910,7 +15928,7 @@
-
+
@@ -20075,6 +20093,7 @@
+
@@ -21699,6 +21718,7 @@
+
@@ -25585,9 +25605,9 @@
-
+
-
+
@@ -27197,7 +27217,7 @@
-
+
@@ -27216,7 +27236,7 @@
-
+
@@ -28015,109 +28035,109 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -28225,11 +28245,9 @@
-
-
-
-
-
+
+
+
@@ -28327,56 +28345,56 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -28603,6 +28621,10 @@
+
+
+
+
@@ -28893,7 +28915,7 @@
-
+
@@ -29855,7 +29877,7 @@
-
+
@@ -30056,6 +30078,7 @@
+
@@ -30066,7 +30089,7 @@
-
+
@@ -30624,166 +30647,32 @@
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -30857,7 +30746,7 @@
-
+
@@ -30899,7 +30788,7 @@
-
+
@@ -31200,7 +31089,7 @@
-
+
@@ -31221,7 +31110,7 @@
-
+
@@ -32870,20 +32759,26 @@
-
-
-
-
+
+
+
+
-
-
+
+
+
+
+
+
+
+
@@ -32892,8 +32787,8 @@
-
-
+
+
@@ -34570,117 +34465,117 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -34693,24 +34588,24 @@
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -34723,63 +34618,63 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -34807,324 +34702,324 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -39119,18 +39014,16 @@
-
+
-
+
-
-
+
-
@@ -39147,7 +39040,6 @@
-
@@ -39155,7 +39047,6 @@
-
@@ -39166,24 +39057,25 @@
-
+
+
-
+
-
+
@@ -39221,13 +39113,13 @@
-
+
-
+
@@ -39235,13 +39127,12 @@
+
-
-
@@ -39258,7 +39149,7 @@
-
+
@@ -39267,13 +39158,13 @@
-
+
-
-
+
+
-
+
@@ -39295,11 +39186,11 @@
-
+
-
+
@@ -39317,18 +39208,18 @@
-
+
+
-
+
-
@@ -39346,7 +39237,7 @@
-
+
@@ -39359,7 +39250,7 @@
-
+
@@ -39367,16 +39258,20 @@
+
+
+
-
+
+
@@ -39417,8 +39312,9 @@
-
+
+
@@ -39432,11 +39328,11 @@
+
-
@@ -39445,7 +39341,7 @@
-
+
@@ -39460,16 +39356,17 @@
-
+
-
+
-
+
+
@@ -39482,9 +39379,10 @@
-
+
+
@@ -39492,19 +39390,17 @@
-
+
-
-
+
-
@@ -39536,8 +39432,6 @@
-
-
@@ -39552,12 +39446,11 @@
-
+
-
@@ -39565,11 +39458,12 @@
-
+
+
@@ -39591,8 +39485,8 @@
-
+
@@ -39600,9 +39494,11 @@
+
-
+
+
@@ -39610,7 +39506,7 @@
-
+
@@ -39625,34 +39521,34 @@
-
-
+
-
+
-
+
-
+
+
@@ -39674,10 +39570,10 @@
-
+
-
-
+
+
@@ -39685,10 +39581,10 @@
-
+
-
+
@@ -39719,7 +39615,6 @@
-
@@ -39742,7 +39637,7 @@
-
+
@@ -39754,14 +39649,14 @@
-
+
-
+
@@ -39771,9 +39666,10 @@
-
+
+
@@ -39786,6 +39682,7 @@
+
@@ -39794,12 +39691,13 @@
-
+
+
-
+
@@ -39808,7 +39706,6 @@
-
@@ -39817,6 +39714,7 @@
+
@@ -39828,12 +39726,12 @@
-
+
-
+
@@ -39852,10 +39750,10 @@
-
+
-
+
@@ -39868,20 +39766,21 @@
-
+
-
+
-
+
+
@@ -39895,7 +39794,6 @@
-
@@ -39933,6 +39831,7 @@
+
@@ -39944,14 +39843,16 @@
-
+
+
-
+
-
+
+
@@ -39978,13 +39879,13 @@
+
-
@@ -39993,9 +39894,9 @@
-
+
-
+
@@ -40022,9 +39923,8 @@
-
+
-
@@ -40041,30 +39941,30 @@
-
-
+
+
-
+
-
+
-
+
-
+
-
+
@@ -40076,19 +39976,22 @@
+
-
-
+
+
+
+
@@ -40100,9 +40003,8 @@
-
-
+
@@ -40111,10 +40013,11 @@
-
+
+
@@ -40140,14 +40043,12 @@
-
-
@@ -40156,7 +40057,7 @@
-
+
@@ -40177,19 +40078,19 @@
-
+
-
+
-
+
@@ -40203,26 +40104,25 @@
-
+
-
+
-
+
-
@@ -40263,7 +40163,8 @@
-
+
+
@@ -40281,7 +40182,7 @@
-
+
@@ -40292,10 +40193,8 @@
-
-
@@ -40309,7 +40208,7 @@
-
+
@@ -40335,11 +40234,10 @@
-
+
-
@@ -40358,9 +40256,11 @@
-
+
+
+
@@ -40369,17 +40269,17 @@
-
+
-
+
-
+
@@ -40388,17 +40288,20 @@
+
+
-
+
+
@@ -40417,8 +40320,8 @@
+
-
@@ -40428,7 +40331,7 @@
-
+
@@ -40437,7 +40340,7 @@
-
+
@@ -40452,8 +40355,6 @@
-
-
@@ -40465,7 +40366,7 @@
-
+
@@ -40473,7 +40374,7 @@
-
+
@@ -40505,7 +40406,6 @@
-
@@ -40514,6 +40414,7 @@
+
@@ -40522,10 +40423,9 @@
-
-
+
@@ -40537,8 +40437,9 @@
+
-
+
@@ -40549,7 +40450,7 @@
-
+
@@ -40559,19 +40460,17 @@
-
-
+
+
-
-
@@ -40582,7 +40481,7 @@
-
+
@@ -40593,7 +40492,6 @@
-
@@ -40604,14 +40502,13 @@
-
-
+
@@ -40640,7 +40537,7 @@
-
+
@@ -40654,19 +40551,18 @@
-
-
+
-
+
-
+
-
+
@@ -40686,11 +40582,11 @@
-
+
-
+
@@ -40702,10 +40598,8 @@
-
-
@@ -40714,9 +40608,10 @@
+
-
+
@@ -40728,11 +40623,10 @@
-
+
-
@@ -40766,18 +40660,18 @@
-
-
+
-
+
+
-
+
@@ -40795,7 +40689,7 @@
-
+
@@ -40810,6 +40704,7 @@
+
@@ -40818,15 +40713,15 @@
-
+
-
+
-
+
@@ -40847,7 +40742,7 @@
-
+
@@ -40855,7 +40750,6 @@
-
@@ -40865,16 +40759,15 @@
+
-
-
+
-
@@ -40891,10 +40784,9 @@
-
-
+
@@ -40902,13 +40794,13 @@
-
+
-
+
@@ -40922,7 +40814,7 @@
-
+
@@ -40932,6 +40824,7 @@
+
@@ -40939,7 +40832,7 @@
-
+
@@ -40959,27 +40852,29 @@
-
+
-
+
+
+
-
+
-
+
@@ -40993,7 +40888,6 @@
-
@@ -41004,7 +40898,7 @@
-
+
@@ -41014,6 +40908,7 @@
+
@@ -41039,27 +40934,25 @@
-
-
-
+
+
-
+
-
+
-
+
-
@@ -41076,6 +40969,7 @@
+
@@ -41083,9 +40977,8 @@
-
-
+
@@ -41101,11 +40994,13 @@
-
+
+
-
+
+
@@ -41138,6 +41033,7 @@
+
@@ -41151,15 +41047,14 @@
-
-
+
-
+
@@ -41169,18 +41064,18 @@
-
+
-
+
@@ -41193,8 +41088,8 @@
-
-
+
+
@@ -41209,8 +41104,9 @@
-
+
+
@@ -41222,7 +41118,6 @@
-
@@ -41244,12 +41139,13 @@
+
-
-
+
+
@@ -41271,7 +41167,7 @@
-
+
@@ -41289,31 +41185,32 @@
+
-
+
-
-
+
-
+
+
-
+
@@ -41324,7 +41221,6 @@
-
@@ -41336,7 +41232,7 @@
-
+
@@ -41344,7 +41240,7 @@
-
+
@@ -41361,7 +41257,7 @@
-
+
@@ -41382,24 +41278,23 @@
-
-
+
-
+
-
+
-
-
-
-
+
+
+
+
@@ -41423,7 +41318,6 @@
-
@@ -41441,11 +41335,11 @@
-
+
-
+
-
+
@@ -41459,11 +41353,12 @@
+
-
+
@@ -41483,33 +41378,32 @@
-
+
-
+
-
-
-
+
+
-
+
@@ -41522,7 +41416,7 @@
-
+
@@ -41531,12 +41425,12 @@
-
+
-
+
@@ -41546,6 +41440,7 @@
+
@@ -41580,11 +41475,13 @@
+
+
@@ -41597,6 +41494,7 @@
+
@@ -41605,16 +41503,18 @@
+
+
-
+
-
+
@@ -41626,7 +41526,7 @@
-
+
@@ -41637,6 +41537,7 @@
+
@@ -41652,13 +41553,10 @@
-
-
-
+
-
-
+
@@ -41670,12 +41568,11 @@
-
+
-
@@ -41731,22 +41628,20 @@
-
+
-
-
+
-
+
-
@@ -41755,7 +41650,7 @@
-
+
@@ -41771,6 +41666,7 @@
+
@@ -41781,7 +41677,7 @@
-
+
@@ -41796,6 +41692,7 @@
+
@@ -41810,7 +41707,7 @@
-
+
@@ -41828,6 +41725,7 @@
+
@@ -41840,23 +41738,23 @@
+
-
+
-
+
-
+
-
-
+
@@ -41873,20 +41771,22 @@
-
+
-
+
-
+
+
-
+
+
@@ -41896,15 +41796,14 @@
-
-
+
-
+
-
+
@@ -41914,20 +41813,21 @@
+
-
-
+
+
-
+
-
+
@@ -41943,7 +41843,6 @@
-
@@ -41951,12 +41850,11 @@
-
+
-
@@ -41982,7 +41880,7 @@
-
+
@@ -42001,7 +41899,7 @@
-
+
@@ -42021,15 +41919,16 @@
-
+
-
+
+
@@ -42058,20 +41957,21 @@
-
+
-
+
+
-
+
@@ -42094,7 +41994,7 @@
-
+
@@ -42103,7 +42003,7 @@
-
+
@@ -42114,8 +42014,9 @@
-
+
+
@@ -42148,7 +42049,7 @@
-
+
@@ -42162,7 +42063,7 @@
-
+
@@ -42170,6 +42071,7 @@
+
@@ -42178,23 +42080,20 @@
-
+
+
-
-
-
-
-
+
@@ -42220,7 +42119,6 @@
-
@@ -42233,7 +42131,7 @@
-
+
@@ -42245,7 +42143,7 @@
-
+
@@ -42253,7 +42151,7 @@
-
+
@@ -42262,6 +42160,7 @@
+
@@ -42273,10 +42172,10 @@
-
+
-
+
@@ -42285,13 +42184,14 @@
-
-
+
+
-
+
+
@@ -42314,23 +42214,22 @@
-
+
-
+
-
-
+
@@ -42351,10 +42250,10 @@
-
-
+
+
-
+
@@ -42366,17 +42265,18 @@
+
-
+
-
+
@@ -42389,7 +42289,7 @@
-
+
@@ -42406,22 +42306,22 @@
+
-
+
-
-
-
+
+
@@ -42470,13 +42370,12 @@
-
+
-
@@ -42497,11 +42396,11 @@
+
-
-
+
@@ -42515,6 +42414,7 @@
+
@@ -42524,7 +42424,8 @@
-
+
+
@@ -42533,7 +42434,7 @@
-
+
@@ -42543,8 +42444,8 @@
-
-
+
+
@@ -42553,6 +42454,7 @@
+
@@ -42577,19 +42479,19 @@
-
-
+
+
+
-
@@ -42599,14 +42501,16 @@
+
+
-
+
@@ -42627,25 +42531,27 @@
+
-
+
+
-
+
-
+
@@ -42653,7 +42559,7 @@
-
+
@@ -42664,16 +42570,16 @@
-
+
-
+
-
+
@@ -42689,7 +42595,6 @@
-
@@ -42699,6 +42604,7 @@
+
@@ -42713,13 +42619,14 @@
+
-
+
@@ -42740,9 +42647,8 @@
-
+
-
@@ -42757,18 +42663,18 @@
-
+
-
+
-
+
@@ -42800,16 +42706,15 @@
-
-
+
-
+
@@ -42817,17 +42722,17 @@
-
+
-
-
+
+
@@ -42838,16 +42743,16 @@
-
+
-
-
+
+
+
-
-
+
@@ -42855,7 +42760,6 @@
-
@@ -42863,7 +42767,7 @@
-
+
@@ -42877,11 +42781,11 @@
-
+
-
+
@@ -42895,20 +42799,19 @@
-
+
-
-
+
@@ -42925,7 +42828,8 @@
-
+
+
@@ -42942,13 +42846,14 @@
-
+
+
+
-
@@ -42969,15 +42874,16 @@
-
+
+
-
+
@@ -42985,21 +42891,19 @@
-
+
-
-
+
-
@@ -43014,6 +42918,7 @@
+
@@ -43024,15 +42929,15 @@
-
-
+
-
+
+
@@ -43048,7 +42953,7 @@
-
+
@@ -43062,14 +42967,14 @@
-
+
-
+
-
+
@@ -43079,10 +42984,10 @@
-
+
@@ -43104,7 +43009,6 @@
-
@@ -43116,7 +43020,7 @@
-
+
@@ -43156,21 +43060,23 @@
+
-
-
-
+
+
+
+
-
+
-
+
@@ -43179,9 +43085,10 @@
+
-
+
@@ -43211,19 +43118,20 @@
-
+
+
-
+
@@ -43232,7 +43140,6 @@
-
@@ -43291,11 +43198,11 @@
-
+
-
+
@@ -43309,7 +43216,7 @@
-
+
@@ -43321,13 +43228,12 @@
-
-
+
@@ -43359,7 +43265,7 @@
-
+
@@ -43375,9 +43281,8 @@
-
-
+
@@ -43387,14 +43292,13 @@
-
-
+
@@ -43403,14 +43307,12 @@
-
-
-
+
@@ -43420,7 +43322,6 @@
-
@@ -43431,6 +43332,7 @@
+
@@ -43443,6 +43345,7 @@
+
@@ -43452,18 +43355,17 @@
-
+
-
-
+
@@ -43482,7 +43384,7 @@
-
+
@@ -43494,7 +43396,6 @@
-
@@ -43533,7 +43434,6 @@
-
@@ -43544,23 +43444,25 @@
-
+
+
-
+
-
-
+
+
+
@@ -43585,6 +43487,7 @@
+
@@ -43592,20 +43495,18 @@
+
-
-
-
@@ -43622,19 +43523,18 @@
-
+
-
-
+
@@ -43651,10 +43551,10 @@
+
-
@@ -43665,7 +43565,7 @@
-
+
@@ -43673,28 +43573,26 @@
+
-
+
-
+
-
-
+
-
-
@@ -43711,10 +43609,10 @@
-
+
-
+
@@ -43725,7 +43623,7 @@
-
+
@@ -43734,9 +43632,8 @@
-
-
+
@@ -43758,29 +43655,32 @@
+
+
+
-
+
-
+
-
+
@@ -43809,14 +43709,14 @@
+
-
-
+
@@ -43828,7 +43728,6 @@
-
@@ -43843,13 +43742,12 @@
-
-
+
@@ -43866,11 +43764,10 @@
-
+
-
@@ -43893,14 +43790,13 @@
-
+
-
@@ -43917,12 +43813,11 @@
-
-
+
@@ -43934,10 +43829,10 @@
+
-
@@ -43948,14 +43843,13 @@
-
+
-
+
-
+
-
@@ -43991,23 +43885,24 @@
-
+
+
-
-
+
+
-
+
-
+
@@ -44020,20 +43915,20 @@
-
-
+
-
+
+
@@ -44050,26 +43945,26 @@
-
+
-
+
-
+
-
+
+
-
@@ -44083,7 +43978,7 @@
-
+
@@ -44101,7 +43996,7 @@
-
+
@@ -44114,12 +44009,13 @@
-
+
+
@@ -44134,20 +44030,20 @@
-
+
-
-
+
+
+
-
@@ -44177,9 +44073,10 @@
+
-
+
@@ -44207,14 +44104,17 @@
+
+
+
@@ -44247,14 +44147,14 @@
-
+
-
+
@@ -44264,15 +44164,15 @@
-
+
-
+
+
-
@@ -44291,11 +44191,11 @@
-
+
-
-
+
+
@@ -44315,7 +44215,7 @@
-
+
@@ -44327,14 +44227,15 @@
-
+
-
-
-
+
+
+
+
@@ -44345,10 +44246,12 @@
+
+
@@ -44368,6 +44271,7 @@
+
@@ -44378,7 +44282,7 @@
-
+
@@ -44407,11 +44311,12 @@
+
-
+
@@ -44421,10 +44326,10 @@
-
-
+
+
@@ -44433,10 +44338,9 @@
-
-
+
@@ -44449,6 +44353,7 @@
+
@@ -44471,10 +44376,9 @@
-
-
+
@@ -44484,14 +44388,13 @@
-
-
+
@@ -44502,9 +44405,10 @@
+
-
+
@@ -44517,7 +44421,7 @@
-
+
@@ -44529,32 +44433,31 @@
-
-
-
+
-
+
-
+
-
+
+
@@ -44565,17 +44468,16 @@
-
-
+
-
+
@@ -44608,7 +44510,7 @@
-
+
@@ -44618,13 +44520,12 @@
-
-
+
@@ -44635,7 +44536,6 @@
-
@@ -44654,9 +44554,8 @@
-
+
-
@@ -44664,17 +44563,17 @@
-
+
-
+
-
+
@@ -44687,17 +44586,17 @@
+
-
+
-
-
+
@@ -44709,7 +44608,7 @@
-
+
@@ -44723,20 +44622,18 @@
-
-
+
-
-
+
-
+
@@ -44744,12 +44641,14 @@
+
+
@@ -44757,14 +44656,14 @@
-
-
+
+
-
+
@@ -44774,7 +44673,6 @@
-
@@ -44795,7 +44693,7 @@
-
+
@@ -44804,8 +44702,6 @@
-
-
@@ -44814,7 +44710,7 @@
-
+
@@ -44826,7 +44722,7 @@
-
+
@@ -44838,7 +44734,6 @@
-
@@ -44851,7 +44746,6 @@
-
@@ -44872,7 +44766,6 @@
-
@@ -44882,7 +44775,6 @@
-
@@ -44907,22 +44799,22 @@
-
+
-
-
+
+
-
+
-
+
@@ -44956,13 +44848,12 @@
-
+
-
-
-
+
+
@@ -45003,17 +44894,17 @@
+
-
+
-
+
+
-
-
@@ -45028,11 +44919,12 @@
-
+
+
@@ -45051,6 +44943,7 @@
+
@@ -45079,19 +44972,18 @@
-
+
+
-
-
@@ -45100,35 +44992,35 @@
-
-
+
-
+
-
+
-
-
+
+
-
+
+
@@ -45148,10 +45040,11 @@
-
+
+
@@ -45163,6 +45056,7 @@
+
@@ -45172,7 +45066,7 @@
-
+
@@ -45192,13 +45086,12 @@
-
-
-
+
+
-
+
@@ -45208,7 +45101,6 @@
-
@@ -45218,7 +45110,7 @@
-
+
@@ -45228,13 +45120,12 @@
-
+
-
+
-
@@ -45257,24 +45148,24 @@
-
+
-
+
-
+
-
+
-
+
-
-
+
+
@@ -45333,7 +45224,6 @@
-
@@ -45377,7 +45267,7 @@
-
+
@@ -45387,14 +45277,14 @@
-
+
-
+
@@ -45418,11 +45308,11 @@
-
+
+
-
@@ -45436,15 +45326,17 @@
+
-
+
-
+
+
@@ -45455,15 +45347,14 @@
-
+
-
-
+
@@ -45501,7 +45392,7 @@
-
+
@@ -45515,7 +45406,7 @@
-
+
@@ -45534,7 +45425,7 @@
-
+
@@ -45543,10 +45434,9 @@
-
+
-
@@ -45554,7 +45444,6 @@
-
@@ -45603,8 +45492,9 @@
-
+
+
@@ -45634,16 +45524,16 @@
-
+
-
+
-
+
@@ -45657,8 +45547,10 @@
+
+
@@ -45671,7 +45563,7 @@
-
+
@@ -45680,6 +45572,7 @@
+
@@ -45692,6 +45585,8 @@
+
+
@@ -45699,7 +45594,6 @@
-
@@ -45733,12 +45627,12 @@
-
+
-
+
-
+
@@ -45758,13 +45652,13 @@
-
-
+
+
@@ -45814,6 +45708,7 @@
+
@@ -45821,7 +45716,7 @@
-
+
@@ -45852,7 +45747,6 @@
-
@@ -45864,9 +45758,9 @@
-
+
@@ -45888,7 +45782,7 @@
-
+
@@ -45902,7 +45796,7 @@
-
+
@@ -45921,9 +45815,9 @@
-
+
-
+
@@ -45944,7 +45838,6 @@
-
@@ -45954,10 +45847,11 @@
-
+
+
@@ -45966,13 +45860,13 @@
+
-
@@ -45985,9 +45879,9 @@
+
-
@@ -46001,17 +45895,16 @@
+
-
+
-
-
@@ -46022,6 +45915,7 @@
+
@@ -46045,6 +45939,7 @@
+
@@ -46060,7 +45955,7 @@
-
+
@@ -46079,27 +45974,30 @@
+
+
-
+
-
+
+
@@ -46112,7 +46010,6 @@
-
@@ -46140,6 +46037,7 @@
+
@@ -46147,8 +46045,7 @@
-
-
+
@@ -46175,7 +46072,7 @@
-
+
@@ -46203,7 +46100,7 @@
-
+
@@ -46221,17 +46118,20 @@
+
+
+
@@ -46241,7 +46141,7 @@
-
+
@@ -46251,7 +46151,7 @@
-
+
@@ -46268,11 +46168,12 @@
+
-
+
@@ -46283,7 +46184,7 @@
-
+
@@ -46296,6 +46197,7 @@
+
@@ -46310,7 +46212,6 @@
-
@@ -46326,9 +46227,9 @@
-
+
-
+
@@ -46355,6 +46256,7 @@
+
@@ -46378,24 +46280,23 @@
-
-
+
+
-
-
+
+
-
@@ -46416,6 +46317,7 @@
+
@@ -46443,7 +46345,6 @@
-
@@ -46452,9 +46353,8 @@
-
+
-
@@ -46482,7 +46382,6 @@
-
@@ -46490,10 +46389,10 @@
-
+
@@ -46505,13 +46404,13 @@
-
+
-
+
@@ -46522,7 +46421,6 @@
-
@@ -46537,7 +46435,6 @@
-
@@ -46551,6 +46448,7 @@
+
@@ -46589,7 +46487,7 @@
-
+
@@ -46597,13 +46495,13 @@
-
+
-
+
@@ -46617,6 +46515,7 @@
+
@@ -46630,12 +46529,12 @@
+
-
@@ -46647,7 +46546,8 @@
-
+
+
@@ -46661,16 +46561,17 @@
+
-
+
-
+
@@ -46679,17 +46580,16 @@
-
-
-
+
+
@@ -46714,19 +46614,17 @@
-
-
-
+
@@ -46735,13 +46633,11 @@
-
-
-
+
@@ -46755,6 +46651,7 @@
+
@@ -46767,7 +46664,7 @@
-
+
@@ -46775,8 +46672,8 @@
+
-
@@ -46784,7 +46681,7 @@
-
+
@@ -46794,14 +46691,14 @@
-
+
-
-
+
+
@@ -46814,7 +46711,6 @@
-
@@ -46839,7 +46735,7 @@
-
+
@@ -46861,7 +46757,6 @@
-
@@ -46870,7 +46765,7 @@
-
+
@@ -46882,6 +46777,7 @@
+
@@ -46892,20 +46788,20 @@
-
+
-
+
@@ -46929,10 +46825,11 @@
-
+
+
@@ -46966,7 +46863,7 @@
-
+
@@ -46978,11 +46875,10 @@
-
+
-
@@ -46998,14 +46894,14 @@
+
-
+
-
-
-
+
+
@@ -47017,7 +46913,7 @@
-
+
@@ -47042,25 +46938,24 @@
-
+
-
+
-
-
+
-
+
-
+
@@ -47079,7 +46974,7 @@
-
+
@@ -47088,19 +46983,20 @@
-
-
+
+
-
+
+
@@ -47109,6 +47005,7 @@
+
@@ -47118,9 +47015,9 @@
+
-
@@ -47152,6 +47049,7 @@
+
@@ -47178,6 +47076,7 @@
+
@@ -47209,7 +47108,7 @@
-
+
@@ -47234,7 +47133,7 @@
-
+
@@ -47254,7 +47153,6 @@
-
@@ -47272,16 +47170,19 @@
+
+
-
+
+
@@ -47290,7 +47191,7 @@
-
+
@@ -47300,11 +47201,10 @@
-
+
-
@@ -47314,12 +47214,12 @@
-
+
-
+
@@ -47328,12 +47228,12 @@
-
+
@@ -47342,11 +47242,10 @@
-
-
+
@@ -47355,13 +47254,14 @@
+
-
+
@@ -47369,18 +47269,18 @@
-
+
-
+
-
+
@@ -47406,7 +47306,7 @@
-
+
@@ -47415,13 +47315,13 @@
-
+
+
-
@@ -47444,7 +47344,7 @@
-
+
@@ -47457,7 +47357,7 @@
-
+
@@ -47465,7 +47365,7 @@
-
+
@@ -47487,14 +47387,14 @@
+
-
-
+
@@ -47507,13 +47407,13 @@
+
-
@@ -47523,8 +47423,6 @@
-
-
@@ -47540,9 +47438,11 @@
-
+
+
-
+
+
@@ -47553,6 +47453,7 @@
+
@@ -47582,11 +47483,12 @@
+
-
+
@@ -47610,7 +47512,7 @@
-
+
@@ -47625,7 +47527,7 @@
-
+
@@ -47633,18 +47535,19 @@
+
-
+
@@ -47652,7 +47555,6 @@
-
@@ -47660,34 +47562,35 @@
-
+
-
+
-
+
-
-
+
-
+
+
+
@@ -47700,14 +47603,14 @@
-
+
-
+
@@ -47753,6 +47656,7 @@
+
@@ -47763,7 +47667,7 @@
-
+
@@ -47790,14 +47694,15 @@
-
+
+
+
-
@@ -47827,50 +47732,47 @@
-
-
+
-
-
-
+
+
-
+
-
+
-
-
+
@@ -47890,29 +47792,27 @@
-
+
-
-
+
-
+
-
@@ -47938,7 +47838,6 @@
-
@@ -47947,7 +47846,6 @@
-
@@ -47959,15 +47857,15 @@
-
-
+
-
+
+
@@ -47975,7 +47873,7 @@
-
+
@@ -47989,6 +47887,7 @@
+
@@ -48005,7 +47904,6 @@
-
@@ -48040,17 +47938,18 @@
-
+
-
-
+
+
+
@@ -48082,7 +47981,6 @@
-
@@ -48094,15 +47992,14 @@
-
-
+
-
+
@@ -48119,14 +48016,15 @@
+
-
+
-
+
@@ -48134,7 +48032,7 @@
-
+
@@ -48149,12 +48047,13 @@
-
+
+
@@ -48172,7 +48071,6 @@
-
@@ -48193,6 +48091,7 @@
+
@@ -48215,7 +48114,7 @@
-
+
@@ -48241,7 +48140,7 @@
-
+
@@ -48254,6 +48153,7 @@
+
@@ -48262,12 +48162,12 @@
-
+
-
+
@@ -48276,14 +48176,12 @@
-
-
+
-
@@ -48302,21 +48200,19 @@
-
-
-
-
+
+
-
+
-
+
@@ -48324,13 +48220,13 @@
-
+
-
+
@@ -48343,8 +48239,8 @@
-
-
+
+
@@ -48368,22 +48264,22 @@
-
-
+
+
-
-
+
+
-
+
@@ -48409,7 +48305,7 @@
-
+
@@ -48418,9 +48314,8 @@
-
+
-
@@ -48442,7 +48337,7 @@
-
+
@@ -48451,21 +48346,21 @@
-
-
-
+
+
-
+
+
@@ -48488,7 +48383,6 @@
-
@@ -48496,16 +48390,18 @@
+
+
-
-
-
+
+
+
@@ -48543,11 +48439,10 @@
-
+
-
@@ -48574,7 +48469,6 @@
-
@@ -48590,27 +48484,28 @@
-
+
+
-
+
-
+
-
+
-
+
@@ -48623,16 +48518,14 @@
-
+
-
-
@@ -48657,11 +48550,9 @@
-
-
@@ -48685,15 +48576,16 @@
-
+
-
+
+
@@ -48714,11 +48606,10 @@
-
-
+
@@ -48742,7 +48633,7 @@
-
+
@@ -48752,15 +48643,15 @@
-
-
+
+
@@ -48768,16 +48659,15 @@
-
+
-
@@ -48790,7 +48680,7 @@
-
+
@@ -48805,15 +48695,14 @@
-
+
-
+
-
@@ -48829,27 +48718,27 @@
-
-
-
+
+
+
-
+
-
+
-
+
-
+
@@ -48867,16 +48756,14 @@
-
-
-
+
@@ -48886,12 +48773,11 @@
-
-
+
@@ -48931,6 +48817,7 @@
+
@@ -48941,6 +48828,7 @@
+
@@ -48948,7 +48836,7 @@
-
+
@@ -48957,7 +48845,7 @@
-
+
@@ -48975,10 +48863,12 @@
+
-
+
+
@@ -48986,13 +48876,12 @@
-
+
-
-
+
-
+
@@ -49005,10 +48894,10 @@
-
+
-
+
@@ -49035,12 +48924,11 @@
-
+
-
@@ -49058,7 +48946,7 @@
-
+
@@ -49068,10 +48956,10 @@
-
+
-
+
@@ -49085,6 +48973,7 @@
+
@@ -49099,18 +48988,19 @@
-
+
+
@@ -49119,8 +49009,9 @@
+
-
+
@@ -49134,7 +49025,8 @@
-
+
+
@@ -49146,10 +49038,10 @@
-
+
-
+
@@ -49166,7 +49058,6 @@
-
@@ -49184,7 +49075,7 @@
-
+
@@ -49207,8 +49098,8 @@
-
+
@@ -49222,9 +49113,11 @@
+
+
@@ -49234,16 +49127,15 @@
-
+
-
-
+
@@ -49255,13 +49147,12 @@
-
+
-
@@ -49271,8 +49162,7 @@
-
-
+
@@ -49280,7 +49170,7 @@
-
+
@@ -49299,7 +49189,7 @@
-
+
@@ -49309,7 +49199,7 @@
-
+
@@ -49317,9 +49207,8 @@
-
-
+
@@ -49331,10 +49220,9 @@
-
+
-
@@ -49353,7 +49241,6 @@
-
@@ -49364,7 +49251,7 @@
-
+
@@ -49378,7 +49265,7 @@
-
+
@@ -49395,6 +49282,7 @@
+
@@ -49404,6 +49292,7 @@
+
@@ -49411,17 +49300,17 @@
-
+
-
+
-
+
@@ -49433,16 +49322,14 @@
-
+
-
-
@@ -49450,6 +49337,7 @@
+
@@ -49464,31 +49352,31 @@
+
-
-
+
-
+
-
+
-
-
+
+
-
+
@@ -49499,11 +49387,12 @@
-
+
-
+
+
@@ -49529,16 +49418,17 @@
+
-
+
-
+
-
+
@@ -49550,6 +49440,7 @@
+
@@ -49562,6 +49453,7 @@
+
@@ -49569,13 +49461,15 @@
-
-
-
+
+
+
+
+
@@ -49590,20 +49484,20 @@
-
-
+
+
-
+
@@ -49621,13 +49515,13 @@
-
+
-
+
@@ -49635,7 +49529,7 @@
-
+
@@ -49646,22 +49540,23 @@
+
-
-
-
+
+
+
@@ -49682,11 +49577,12 @@
-
+
+
-
+
@@ -49712,7 +49608,7 @@
-
+
@@ -49723,22 +49619,20 @@
-
+
-
-
-
+
-
+
@@ -49753,7 +49647,7 @@
-
+
@@ -49773,15 +49667,15 @@
-
+
-
+
@@ -49794,13 +49688,13 @@
-
+
-
+
@@ -49812,7 +49706,6 @@
-
@@ -49834,11 +49727,11 @@
-
+
-
+
@@ -49848,7 +49741,7 @@
-
+
@@ -49857,18 +49750,20 @@
-
+
+
+
-
+
-
+
@@ -49891,18 +49786,17 @@
-
-
-
+
+
@@ -49911,14 +49805,15 @@
-
+
+
+
-
@@ -49927,10 +49822,9 @@
-
-
+
@@ -49945,14 +49839,12 @@
-
-
@@ -49966,7 +49858,7 @@
-
+
@@ -49997,13 +49889,13 @@
-
+
-
+
@@ -50011,16 +49903,16 @@
+
-
+
-
@@ -50036,7 +49928,7 @@
-
+
@@ -50050,7 +49942,6 @@
-
@@ -50071,7 +49962,7 @@
-
+
@@ -50082,18 +49973,18 @@
-
+
-
+
@@ -50102,7 +49993,7 @@
-
+
@@ -50113,7 +50004,7 @@
-
+
@@ -50134,10 +50025,11 @@
-
+
+
@@ -50147,14 +50039,14 @@
-
+
-
+
@@ -50166,6 +50058,7 @@
+
@@ -50178,12 +50071,10 @@
-
+
-
-
@@ -50221,9 +50112,10 @@
-
+
+
@@ -50250,11 +50142,12 @@
+
-
+
@@ -50271,7 +50164,6 @@
-
@@ -50280,11 +50172,11 @@
-
+
-
+
@@ -50299,7 +50191,6 @@
-
@@ -50311,7 +50202,7 @@
-
+
@@ -50319,7 +50210,7 @@
-
+
@@ -50343,7 +50234,7 @@
-
+
@@ -50358,11 +50249,12 @@
-
+
-
+
+
@@ -50383,26 +50275,26 @@
-
+
-
+
-
+
-
-
+
+
@@ -50426,7 +50318,6 @@
-
@@ -50445,17 +50336,18 @@
+
-
+
-
+
-
+
@@ -50468,7 +50360,6 @@
-
@@ -50489,7 +50380,6 @@
-
@@ -50508,17 +50398,17 @@
-
+
+
-
@@ -50572,6 +50462,7 @@
+
@@ -50579,12 +50470,13 @@
-
+
+
-
+
@@ -50597,7 +50489,7 @@
-
+
@@ -50613,6 +50505,7 @@
+
@@ -50624,20 +50517,19 @@
-
-
+
+
-
+
-
@@ -50647,7 +50539,7 @@
-
+
@@ -50658,7 +50550,6 @@
-
@@ -50680,12 +50571,12 @@
-
+
-
+
@@ -50697,7 +50588,7 @@
-
+
@@ -50705,7 +50596,9 @@
+
+
@@ -50717,10 +50610,11 @@
-
+
+
@@ -50734,7 +50628,6 @@
-
@@ -50743,6 +50636,7 @@
+
@@ -50761,18 +50655,17 @@
+
+
-
-
-
@@ -50780,7 +50673,6 @@
-
@@ -50791,7 +50683,6 @@
-
@@ -50808,22 +50699,19 @@
-
-
-
-
-
+
+
-
+
@@ -50843,10 +50731,11 @@
-
+
+
@@ -50880,7 +50769,7 @@
-
+
@@ -50892,19 +50781,18 @@
-
-
+
@@ -50918,6 +50806,7 @@
+
@@ -50932,7 +50821,6 @@
-
@@ -50960,11 +50848,10 @@
-
+
-
@@ -50979,11 +50866,10 @@
-
+
-
@@ -51005,12 +50891,13 @@
-
+
+
-
+
-
+
@@ -51018,6 +50905,7 @@
+
@@ -51043,19 +50931,19 @@
-
+
-
+
-
+
@@ -51073,7 +50961,7 @@
-
+
@@ -51110,14 +50998,14 @@
-
+
-
+
@@ -51134,7 +51022,6 @@
-
@@ -51145,9 +51032,10 @@
-
+
+
-
+
@@ -51176,17 +51064,19 @@
+
+
+
-
@@ -51194,10 +51084,9 @@
-
+
-
@@ -51226,7 +51115,6 @@
-
@@ -51236,7 +51124,6 @@
-
@@ -51249,19 +51136,17 @@
-
+
-
-
+
-
-
+
@@ -51272,9 +51157,8 @@
-
-
-
+
+
@@ -51282,9 +51166,8 @@
-
-
+
@@ -51295,6 +51178,7 @@
+
@@ -51304,7 +51188,7 @@
-
+
@@ -51319,7 +51203,6 @@
-
@@ -51327,10 +51210,9 @@
-
-
+
-
+
@@ -51349,21 +51231,18 @@
-
-
+
-
+
-
-
-
+
@@ -51374,24 +51253,23 @@
-
+
-
+
-
+
-
@@ -51411,15 +51289,15 @@
-
+
-
+
-
+
@@ -51431,6 +51309,7 @@
+
@@ -51439,9 +51318,8 @@
-
-
+
@@ -51456,17 +51334,18 @@
-
+
+
-
+
-
+
@@ -51500,7 +51379,7 @@
-
+
@@ -51535,11 +51414,11 @@
-
+
-
+
@@ -51562,9 +51441,10 @@
-
+
+
-
+
@@ -51579,7 +51459,7 @@
-
+
@@ -51594,6 +51474,7 @@
+
@@ -51607,7 +51488,7 @@
-
+
@@ -51635,7 +51516,6 @@
-
@@ -51660,7 +51540,6 @@
-
@@ -51672,7 +51551,7 @@
-
+
@@ -51686,7 +51565,6 @@
-
@@ -51707,22 +51585,19 @@
-
-
-
+
-
-
+
@@ -51745,21 +51620,20 @@
-
+
-
+
-
+
-
+
-
@@ -51783,6 +51657,7 @@
+
@@ -51800,7 +51675,6 @@
-
@@ -51820,11 +51694,11 @@
-
-
+
+
-
+
@@ -51856,8 +51730,8 @@
-
+
@@ -51866,12 +51740,12 @@
-
+
-
+
@@ -51891,7 +51765,7 @@
-
+
@@ -51914,19 +51788,17 @@
-
+
+
-
-
-
@@ -51937,6 +51809,7 @@
+
@@ -51949,14 +51822,12 @@
-
-
-
+
@@ -51966,6 +51837,7 @@
+
@@ -51978,17 +51850,17 @@
+
-
+
-
-
+
@@ -52000,6 +51872,7 @@
+
@@ -52011,7 +51884,6 @@
-
@@ -52038,7 +51910,6 @@
-
@@ -52051,19 +51922,21 @@
+
-
+
-
+
-
+
+
@@ -52079,11 +51952,12 @@
+
-
+
@@ -52098,7 +51972,6 @@
-
@@ -52107,18 +51980,17 @@
-
-
+
-
-
+
+
@@ -52127,12 +51999,12 @@
-
+
-
+
@@ -52140,6 +52012,7 @@
+
@@ -52151,10 +52024,10 @@
+
-
@@ -52162,7 +52035,7 @@
-
+
@@ -52202,10 +52075,10 @@
-
+
-
+
@@ -52222,9 +52095,9 @@
-
+
@@ -52252,7 +52125,6 @@
-
@@ -52261,6 +52133,7 @@
+
@@ -52269,9 +52142,9 @@
-
-
+
+
@@ -52288,13 +52161,14 @@
-
+
-
+
+
@@ -52304,6 +52178,7 @@
+
@@ -52312,10 +52187,11 @@
-
+
-
-
+
+
+
@@ -52334,18 +52210,18 @@
-
+
-
+
-
-
+
+
@@ -52355,11 +52231,10 @@
-
-
+
@@ -52391,17 +52266,17 @@
+
-
-
+
@@ -52409,11 +52284,11 @@
-
+
-
+
@@ -52424,8 +52299,10 @@
+
+
@@ -52449,6 +52326,7 @@
+
@@ -52457,7 +52335,7 @@
-
+
@@ -52500,7 +52378,6 @@
-
@@ -52510,7 +52387,7 @@
-
+
@@ -52522,9 +52399,7 @@
-
-
@@ -52537,7 +52412,7 @@
-
+
@@ -52567,26 +52442,26 @@
-
+
-
+
-
-
+
-
+
+
+
-
@@ -52600,18 +52475,17 @@
-
+
-
-
+
@@ -52645,6 +52519,7 @@
+
@@ -52664,7 +52539,7 @@
-
+
@@ -52673,7 +52548,7 @@
-
+
@@ -52687,7 +52562,7 @@
-
+
@@ -52713,12 +52588,12 @@
-
+
-
+
@@ -52732,7 +52607,7 @@
-
+
@@ -52752,7 +52627,6 @@
-
@@ -52767,7 +52641,6 @@
-
@@ -52788,11 +52661,12 @@
+
-
+
@@ -52817,7 +52691,7 @@
-
+
@@ -52833,8 +52707,9 @@
-
+
+
@@ -52848,14 +52723,14 @@
-
+
-
+
-
+
@@ -52863,8 +52738,7 @@
-
-
+
@@ -52872,10 +52746,10 @@
+
-
@@ -52894,29 +52768,30 @@
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -52927,6 +52802,7 @@
+
@@ -52935,6 +52811,7 @@
+
@@ -52944,7 +52821,6 @@
-
@@ -52979,14 +52855,14 @@
-
+
-
+
@@ -53002,8 +52878,9 @@
+
+
-
@@ -53012,8 +52889,7 @@
-
-
+
@@ -53024,30 +52900,31 @@
-
-
+
-
+
+
-
+
-
+
+
-
+
@@ -53058,7 +52935,7 @@
-
+
@@ -53070,10 +52947,9 @@
-
+
-
@@ -53084,7 +52960,6 @@
-
@@ -53093,34 +52968,36 @@
-
+
-
+
+
+
-
+
-
+
@@ -53134,20 +53011,21 @@
+
-
+
-
+
+
-
@@ -53177,18 +53055,16 @@
-
+
-
+
-
-
@@ -53205,7 +53081,6 @@
-
@@ -53238,6 +53113,7 @@
+
@@ -53248,7 +53124,7 @@
-
+
@@ -53263,18 +53139,17 @@
-
+
-
+
+
-
+
-
-
@@ -53347,7 +53222,7 @@
-
+
@@ -53355,7 +53230,7 @@
-
+
@@ -53368,15 +53243,16 @@
+
-
+
-
+
@@ -53390,7 +53266,6 @@
-
@@ -53402,7 +53277,7 @@
-
+
@@ -53424,15 +53299,17 @@
+
-
+
+
@@ -53448,7 +53325,7 @@
-
+
@@ -53458,7 +53335,7 @@
-
+
@@ -53488,7 +53365,7 @@
-
+
@@ -53521,7 +53398,7 @@
-
+
@@ -53533,16 +53410,17 @@
-
+
+
-
+
@@ -53551,13 +53429,14 @@
-
+
+
@@ -53571,11 +53450,12 @@
-
+
+
-
+
@@ -53589,9 +53469,9 @@
-
+
-
+
@@ -53613,7 +53493,7 @@
-
+
@@ -53636,14 +53516,12 @@
-
-
+
-
@@ -53657,17 +53535,17 @@
+
-
-
+
-
+
@@ -53681,12 +53559,12 @@
-
+
-
+
@@ -53701,16 +53579,16 @@
-
-
+
+
-
+
-
+
@@ -53718,17 +53596,17 @@
-
+
-
+
@@ -53764,7 +53642,7 @@
-
+
@@ -53786,7 +53664,6 @@
-
@@ -53805,6 +53682,7 @@
+
@@ -53812,13 +53690,15 @@
-
+
+
+
-
+
@@ -53830,7 +53710,6 @@
-
@@ -53838,7 +53717,7 @@
-
+
@@ -53860,7 +53739,7 @@
-
+
@@ -53881,6 +53760,7 @@
+
@@ -53896,12 +53776,13 @@
+
+
-
@@ -53913,13 +53794,13 @@
-
+
-
+
@@ -53929,7 +53810,7 @@
-
+
@@ -53939,10 +53820,12 @@
+
+
@@ -53973,18 +53856,18 @@
-
-
+
+
-
+
@@ -53996,7 +53879,7 @@
-
+
@@ -54056,16 +53939,14 @@
-
-
-
+
-
+
@@ -54076,6 +53957,7 @@
+
@@ -54089,9 +53971,10 @@
-
+
+
@@ -54101,6 +53984,7 @@
+
@@ -54122,13 +54006,14 @@
-
+
+
@@ -54136,7 +54021,7 @@
-
+
@@ -54145,7 +54030,7 @@
-
+
@@ -54153,7 +54038,6 @@
-
@@ -54161,6 +54045,7 @@
+
@@ -54172,7 +54057,7 @@
-
+
@@ -54193,15 +54078,15 @@
+
-
-
+
@@ -54214,7 +54099,7 @@
-
+
@@ -54230,8 +54115,9 @@
-
+
+
@@ -54243,37 +54129,35 @@
+
-
-
+
-
-
+
-
+
-
@@ -54284,21 +54168,21 @@
-
+
-
-
+
+
@@ -54309,7 +54193,6 @@
-
@@ -54321,11 +54204,10 @@
-
+
-
@@ -54334,26 +54216,25 @@
-
+
+
-
-
-
+
+
-
@@ -54378,6 +54259,7 @@
+
@@ -54394,19 +54276,19 @@
-
+
-
+
-
+
-
+
@@ -54420,7 +54302,6 @@
-
@@ -54429,10 +54310,9 @@
-
+
-
@@ -54450,7 +54330,7 @@
-
+
@@ -54458,7 +54338,7 @@
-
+
@@ -54467,14 +54347,13 @@
-
+
-
@@ -54510,8 +54389,7 @@
-
-
+
@@ -54522,12 +54400,12 @@
-
+
@@ -54535,17 +54413,17 @@
+
+
-
-
@@ -54578,7 +54456,7 @@
-
+
@@ -54588,13 +54466,13 @@
-
+
-
+
@@ -54615,7 +54493,7 @@
-
+
@@ -54629,7 +54507,8 @@
-
+
+
@@ -54641,10 +54520,9 @@
-
-
+
@@ -54676,7 +54554,7 @@
-
+
@@ -54689,7 +54567,7 @@
-
+
@@ -54706,7 +54584,7 @@
-
+
@@ -54715,7 +54593,7 @@
-
+
@@ -54726,8 +54604,8 @@
+
-
@@ -54735,6 +54613,7 @@
+
@@ -54766,11 +54645,12 @@
-
+
+
@@ -54799,7 +54679,7 @@
-
+
@@ -54808,7 +54688,6 @@
-
@@ -54819,6 +54698,7 @@
+
@@ -54830,8 +54710,7 @@
-
-
+
@@ -54845,7 +54724,7 @@
-
+
@@ -54856,33 +54735,35 @@
-
+
+
-
+
+
-
+
-
+
-
+
-
+
@@ -54890,6 +54771,7 @@
+
@@ -54908,7 +54790,7 @@
-
+
@@ -54917,7 +54799,6 @@
-
@@ -54931,9 +54812,10 @@
-
+
-
+
+
@@ -54955,7 +54837,6 @@
-
@@ -54975,6 +54856,7 @@
+
@@ -54983,6 +54865,7 @@
+
@@ -55020,7 +54903,8 @@
-
+
+
@@ -55035,30 +54919,30 @@
-
+
-
+
-
+
-
-
+
+
@@ -55071,7 +54955,7 @@
-
+
@@ -55085,14 +54969,13 @@
-
+
-
-
+
@@ -55102,7 +54985,7 @@
-
+
@@ -55131,6 +55014,7 @@
+
@@ -55142,12 +55026,12 @@
-
+
-
+
@@ -55160,13 +55044,12 @@
-
-
+
@@ -55189,7 +55072,7 @@
-
+
@@ -55197,6 +55080,7 @@
+
@@ -55215,7 +55099,7 @@
-
+
@@ -55248,39 +55132,36 @@
-
+
-
-
-
-
+
-
+
+
-
@@ -55298,7 +55179,7 @@
-
+
@@ -55306,6 +55187,7 @@
+
@@ -55334,8 +55216,8 @@
-
+
@@ -55348,7 +55230,7 @@
-
+
@@ -55358,11 +55240,10 @@
-
-
+
@@ -55380,21 +55261,22 @@
-
+
-
+
-
+
-
+
+
@@ -55411,14 +55293,12 @@
-
+
-
-
@@ -55431,8 +55311,7 @@
-
-
+
@@ -55441,12 +55320,12 @@
+
-
-
+
@@ -55466,7 +55345,6 @@
-
@@ -55478,11 +55356,10 @@
-
+
-
-
+
@@ -55502,13 +55379,13 @@
-
+
-
+
@@ -55521,8 +55398,10 @@
+
+
@@ -55531,7 +55410,6 @@
-
@@ -55546,15 +55424,14 @@
-
+
-
+
-
@@ -55567,8 +55444,8 @@
+
-
@@ -55581,12 +55458,14 @@
+
+
@@ -55594,14 +55473,14 @@
-
+
-
+
@@ -55612,7 +55491,8 @@
-
+
+
@@ -55660,7 +55540,7 @@
-
+
@@ -55677,16 +55557,13 @@
-
-
-
+
+
-
-
-
+
@@ -55696,17 +55573,18 @@
+
-
+
+
-
+
-
@@ -55716,11 +55594,11 @@
-
+
-
+
@@ -55729,13 +55607,13 @@
-
+
@@ -55745,7 +55623,8 @@
-
+
+
@@ -55758,17 +55637,18 @@
-
+
+
+
-
@@ -55776,8 +55656,8 @@
-
-
+
+
@@ -55787,12 +55667,11 @@
-
+
-
@@ -55807,6 +55686,7 @@
+
@@ -55824,7 +55704,6 @@
-
@@ -55833,6 +55712,7 @@
+
@@ -55843,14 +55723,13 @@
-
+
-
@@ -55860,7 +55739,6 @@
-
@@ -55870,6 +55748,7 @@
+
@@ -55912,13 +55791,12 @@
-
+
-
-
+
@@ -55931,13 +55809,11 @@
-
-
@@ -55952,15 +55828,14 @@
-
+
-
+
-
@@ -55994,8 +55869,8 @@
-
-
+
+
@@ -56006,14 +55881,13 @@
-
-
+
-
+
@@ -56037,8 +55911,8 @@
+
-
@@ -56058,7 +55932,6 @@
-
@@ -56076,7 +55949,7 @@
-
+
@@ -56085,7 +55958,6 @@
-
@@ -56109,15 +55981,16 @@
+
-
+
+
-
+
-
@@ -56125,10 +55998,10 @@
-
+
+
-
@@ -56144,6 +56017,7 @@
+
@@ -56184,15 +56058,15 @@
-
+
-
+
-
+
@@ -56200,7 +56074,6 @@
-
@@ -56230,17 +56103,18 @@
-
+
-
+
+
@@ -56258,23 +56132,26 @@
-
+
-
+
+
+
+
@@ -56289,24 +56166,23 @@
-
+
-
+
-
+
-
@@ -56328,7 +56204,7 @@
-
+
@@ -56355,7 +56231,6 @@
-
@@ -56363,15 +56238,14 @@
-
+
-
@@ -56395,12 +56269,13 @@
-
+
+
@@ -56410,12 +56285,12 @@
-
-
+
+
-
+
-
+
@@ -56429,18 +56304,17 @@
-
-
+
-
+
@@ -56450,16 +56324,15 @@
-
-
+
-
+
-
+
@@ -56467,7 +56340,6 @@
-
@@ -56478,7 +56350,6 @@
-
@@ -56486,7 +56357,6 @@
-
@@ -56517,14 +56387,16 @@
-
+
+
+
@@ -56543,7 +56415,6 @@
-
@@ -56553,17 +56424,17 @@
-
-
+
+
-
+
@@ -56574,7 +56445,7 @@
-
+
@@ -56583,27 +56454,25 @@
-
-
+
+
+
-
-
-
+
-
-
+
@@ -56613,7 +56482,6 @@
-
@@ -56625,18 +56493,17 @@
-
-
+
+
-
@@ -56661,15 +56528,15 @@
-
+
-
+
-
+
@@ -56685,10 +56552,12 @@
+
+
-
+
@@ -56702,13 +56571,13 @@
-
+
-
+
@@ -56719,7 +56588,7 @@
-
+
@@ -56750,17 +56619,16 @@
-
-
+
-
+
-
+
@@ -56777,26 +56645,24 @@
-
-
+
-
-
+
-
+
@@ -56809,7 +56675,7 @@
-
+
@@ -56818,7 +56684,6 @@
-
@@ -56827,32 +56692,30 @@
-
+
-
-
-
+
-
+
+
-
-
+
@@ -56866,7 +56729,7 @@
-
+
@@ -56879,6 +56742,7 @@
+
@@ -56926,16 +56790,14 @@
-
-
+
-
@@ -56948,7 +56810,7 @@
-
+
@@ -56964,12 +56826,10 @@
-
-
@@ -56991,6 +56851,7 @@
+
@@ -56998,16 +56859,16 @@
+
-
+
-
-
+
@@ -57030,7 +56891,7 @@
-
+
@@ -57048,21 +56909,21 @@
-
+
+
-
-
+
-
+
@@ -57070,9 +56931,7 @@
-
-
@@ -57083,7 +56942,7 @@
-
+
@@ -57091,7 +56950,6 @@
-
@@ -57099,8 +56957,8 @@
-
-
+
+
@@ -57119,7 +56977,7 @@
-
+
@@ -57139,7 +56997,7 @@
-
+
@@ -57166,8 +57024,8 @@
-
-
+
+
@@ -57180,10 +57038,10 @@
-
+
-
+
@@ -57197,7 +57055,7 @@
-
+
@@ -57213,9 +57071,8 @@
-
+
-
@@ -57224,19 +57081,19 @@
-
+
-
+
-
+
-
+
@@ -57244,10 +57101,11 @@
-
+
-
+
+
@@ -57263,35 +57121,34 @@
+
+
-
-
+
-
+
-
-
-
+
@@ -57306,10 +57163,10 @@
-
+
-
+
@@ -57322,13 +57179,14 @@
-
+
+
@@ -57336,7 +57194,7 @@
-
+
@@ -57348,7 +57206,7 @@
-
+
@@ -57358,6 +57216,7 @@
+
@@ -57371,12 +57230,11 @@
-
+
-
@@ -57387,15 +57245,14 @@
-
-
+
-
-
+
+
@@ -57422,7 +57279,6 @@
-
@@ -57430,13 +57286,13 @@
-
+
+
-
@@ -57446,7 +57302,7 @@
-
+
@@ -57475,10 +57331,10 @@
-
+
-
+
@@ -57490,7 +57346,6 @@
-
@@ -57499,14 +57354,14 @@
-
+
-
+
@@ -57524,8 +57379,7 @@
-
-
+
@@ -57550,6 +57404,7 @@
+
@@ -57573,9 +57428,8 @@
-
+
-
@@ -57591,6 +57445,7 @@
+
@@ -57602,7 +57457,7 @@
-
+
@@ -57614,14 +57469,13 @@
-
+
-
@@ -57635,7 +57489,7 @@
-
+
@@ -57644,7 +57498,6 @@
-
@@ -57652,11 +57505,10 @@
-
+
-
@@ -57680,6 +57532,7 @@
+
@@ -57700,7 +57553,6 @@
-
@@ -57716,7 +57568,7 @@
-
+
@@ -57730,10 +57582,10 @@
-
+
-
+
@@ -57746,6 +57598,7 @@
+
@@ -57769,7 +57622,7 @@
-
+
@@ -57808,7 +57661,7 @@
-
+
@@ -57826,8 +57679,7 @@
-
-
+
@@ -57835,8 +57687,8 @@
+
-
@@ -57844,10 +57696,12 @@
+
+
@@ -57855,14 +57709,14 @@
-
-
+
-
+
+
@@ -57888,23 +57742,25 @@
-
+
+
-
+
-
+
+
@@ -57914,7 +57770,7 @@
-
+
@@ -57930,8 +57786,7 @@
-
-
+
@@ -57940,6 +57795,8 @@
+
+
@@ -57948,12 +57805,11 @@
-
-
+
@@ -57985,7 +57841,8 @@
-
+
+
@@ -57996,17 +57853,15 @@
-
-
+
-
@@ -58018,14 +57873,15 @@
-
+
-
+
-
+
+
@@ -58044,7 +57900,8 @@
-
+
+
@@ -58056,17 +57913,16 @@
-
+
-
@@ -58097,8 +57953,7 @@
-
-
+
@@ -58107,7 +57962,6 @@
-
@@ -58140,7 +57994,7 @@
-
+
@@ -58158,9 +58012,8 @@
-
+
-
@@ -58168,7 +58021,6 @@
-
@@ -58185,14 +58037,15 @@
+
-
-
+
+
@@ -58210,12 +58063,12 @@
-
+
-
+
@@ -58229,7 +58082,9 @@
+
+
@@ -58239,9 +58094,9 @@
-
+
-
+
@@ -58266,7 +58121,7 @@
-
+
@@ -58274,6 +58129,7 @@
+
@@ -58297,7 +58153,7 @@
-
+
@@ -58306,18 +58162,19 @@
+
-
+
-
+
@@ -58326,7 +58183,7 @@
-
+
@@ -58350,7 +58207,7 @@
-
+
@@ -58361,9 +58218,10 @@
+
-
+
@@ -58376,7 +58234,6 @@
-
@@ -58387,17 +58244,15 @@
-
-
-
+
@@ -58405,24 +58260,22 @@
-
-
-
-
+
-
+
+
@@ -58430,7 +58283,7 @@
-
+
@@ -58438,9 +58291,10 @@
-
+
+
@@ -58449,16 +58303,17 @@
+
-
+
-
+
@@ -58471,50 +58326,49 @@
-
-
+
-
+
+
-
+
-
-
+
+
-
+
-
+
-
+
-
@@ -58522,11 +58376,12 @@
+
-
+
@@ -58542,7 +58397,6 @@
-
@@ -58560,12 +58414,12 @@
-
+
@@ -58583,7 +58437,6 @@
-
@@ -58592,22 +58445,22 @@
-
+
-
+
-
+
-
-
+
+
@@ -58618,7 +58471,6 @@
-
@@ -58634,9 +58486,10 @@
-
+
+
-
+
@@ -58648,17 +58501,18 @@
-
+
+
-
+
-
+
@@ -58697,12 +58551,12 @@
-
+
-
+
@@ -58712,14 +58566,14 @@
-
+
-
-
+
+
-
+
@@ -58728,7 +58582,7 @@
-
+
@@ -58745,11 +58599,9 @@
-
-
-
+
@@ -58778,11 +58630,12 @@
+
-
+
@@ -58791,14 +58644,12 @@
-
-
-
+
@@ -58813,7 +58664,7 @@
-
+
@@ -58841,14 +58692,15 @@
+
-
+
-
+
@@ -58859,7 +58711,7 @@
-
+
@@ -58908,32 +58760,28 @@
-
-
-
-
-
+
-
-
+
+
-
+
-
+
@@ -58945,7 +58793,7 @@
-
+
@@ -58955,10 +58803,9 @@
-
+
-
@@ -58969,16 +58816,17 @@
-
+
-
+
+
@@ -58997,10 +58845,10 @@
-
+
@@ -59014,11 +58862,10 @@
-
+
-
@@ -59032,7 +58879,7 @@
-
+
@@ -59044,7 +58891,9 @@
-
+
+
+
@@ -59054,8 +58903,7 @@
-
-
+
@@ -59064,14 +58912,16 @@
+
+
+
-
@@ -59081,10 +58931,9 @@
-
+
-
@@ -59093,8 +58942,8 @@
-
-
+
+
@@ -59121,14 +58970,13 @@
-
+
-
@@ -59173,7 +59021,7 @@
-
+
@@ -59181,7 +59029,7 @@
-
+
@@ -59194,9 +59042,10 @@
+
-
+
@@ -59216,7 +59065,6 @@
-
@@ -59230,10 +59078,9 @@
-
-
+
@@ -59246,7 +59093,7 @@
-
+
@@ -59267,7 +59114,6 @@
-
@@ -59282,7 +59128,6 @@
-
@@ -59319,12 +59164,11 @@
-
-
+
@@ -59341,7 +59185,7 @@
-
+
@@ -59353,6 +59197,7 @@
+
@@ -59361,10 +59206,9 @@
-
+
-
@@ -59381,15 +59225,15 @@
-
+
-
+
@@ -59398,17 +59242,17 @@
-
+
-
+
-
+
@@ -59444,6 +59288,7 @@
+
@@ -59452,7 +59297,6 @@
-
@@ -59463,7 +59307,7 @@
-
+
@@ -59489,8 +59333,10 @@
+
+
@@ -59500,7 +59346,7 @@
-
+
@@ -59533,7 +59379,6 @@
-
@@ -59550,6 +59395,7 @@
+
@@ -59557,18 +59403,17 @@
-
+
-
-
+
-
+
@@ -59580,11 +59425,10 @@
-
+
-
@@ -59605,6 +59449,7 @@
+
@@ -59632,8 +59477,9 @@
+
-
+
@@ -59646,7 +59492,7 @@
-
+
@@ -59666,7 +59512,6 @@
-
@@ -59684,16 +59529,16 @@
-
+
-
+
@@ -59709,6 +59554,7 @@
+
@@ -59739,7 +59585,7 @@
-
+
@@ -59759,11 +59605,11 @@
-
+
-
+
@@ -59783,7 +59629,6 @@
-
@@ -59793,7 +59638,8 @@
-
+
+
@@ -59806,8 +59652,6 @@
-
-
@@ -59815,14 +59659,15 @@
+
-
+
-
+
@@ -59832,15 +59677,14 @@
-
+
-
-
+
@@ -59851,7 +59695,6 @@
-
@@ -59867,7 +59710,7 @@
-
+
@@ -59892,8 +59735,9 @@
-
+
+
@@ -59919,31 +59763,30 @@
-
+
-
-
-
+
+
-
+
-
-
+
+
@@ -59955,15 +59798,17 @@
+
-
+
+
@@ -59994,7 +59839,7 @@
-
+
@@ -60010,17 +59855,18 @@
-
+
+
-
-
-
+
+
+
@@ -60029,23 +59875,24 @@
-
+
+
-
+
-
+
-
+
-
+
@@ -60066,7 +59913,6 @@
-
@@ -60074,7 +59920,7 @@
-
+
@@ -60085,6 +59931,7 @@
+
@@ -60104,9 +59951,8 @@
-
-
+
@@ -60120,7 +59966,7 @@
-
+
@@ -60132,13 +59978,12 @@
-
+
-
-
+
@@ -60153,7 +59998,7 @@
-
+
@@ -60166,7 +60011,7 @@
-
+
@@ -60177,7 +60022,6 @@
-
@@ -60221,7 +60065,7 @@
-
+
@@ -60229,7 +60073,6 @@
-
@@ -60241,7 +60084,6 @@
-
@@ -60289,11 +60131,9 @@
-
-
-
+
@@ -60301,10 +60141,8 @@
-
-
@@ -60318,6 +60156,7 @@
+
@@ -60347,6 +60186,7 @@
+
@@ -60354,7 +60194,6 @@
-
@@ -60362,7 +60201,7 @@
-
+
@@ -60370,18 +60209,16 @@
-
+
-
-
-
+
@@ -60405,26 +60242,26 @@
+
-
+
-
-
+
@@ -60435,7 +60272,7 @@
-
+
@@ -60455,6 +60292,7 @@
+
@@ -60467,42 +60305,41 @@
+
-
+
-
-
-
+
-
-
+
+
-
+
-
-
+
-
+
+
@@ -60511,10 +60348,8 @@
-
-
@@ -60529,13 +60364,12 @@
-
-
+
@@ -60546,10 +60380,9 @@
-
-
+
@@ -60572,6 +60405,7 @@
+
@@ -60585,7 +60419,6 @@
-
@@ -60604,10 +60437,10 @@
-
+
-
+
@@ -60621,7 +60454,7 @@
-
+
@@ -60649,10 +60482,11 @@
-
+
+
@@ -60671,21 +60505,19 @@
-
+
-
-
+
-
-
+
@@ -60720,6 +60552,7 @@
+
@@ -60729,6 +60562,7 @@
+
@@ -60742,7 +60576,6 @@
-
@@ -60765,11 +60598,12 @@
-
+
-
+
+
@@ -60785,17 +60619,17 @@
+
-
+
+
-
-
@@ -60814,9 +60648,10 @@
-
+
+
-
+
@@ -60828,15 +60663,16 @@
+
-
+
-
+
@@ -60860,12 +60696,13 @@
-
+
+
@@ -60881,7 +60718,6 @@
-
@@ -60902,15 +60738,17 @@
+
-
+
+
@@ -60924,7 +60762,7 @@
-
+
@@ -60942,7 +60780,7 @@
-
+
@@ -60954,13 +60792,13 @@
-
+
-
+
@@ -60968,7 +60806,7 @@
-
+
@@ -60982,7 +60820,6 @@
-
@@ -60993,25 +60830,24 @@
-
+
-
-
+
-
+
-
+
-
+
@@ -61024,7 +60860,7 @@
-
+
@@ -61036,7 +60872,7 @@
-
+
@@ -61044,7 +60880,7 @@
-
+
@@ -61053,7 +60889,7 @@
-
+
@@ -61063,7 +60899,7 @@
-
+
@@ -61079,6 +60915,7 @@
+
@@ -61086,7 +60923,7 @@
-
+
@@ -61099,10 +60936,10 @@
-
+
-
+
@@ -61132,23 +60969,26 @@
-
-
+
+
+
-
+
+
+
@@ -61169,19 +61009,19 @@
-
+
-
+
-
+
@@ -61190,7 +61030,7 @@
-
+
@@ -61210,6 +61050,7 @@
+
@@ -61231,6 +61072,7 @@
+
@@ -61251,7 +61093,7 @@
-
+
@@ -61259,19 +61101,18 @@
-
+
-
+
-
+
-
@@ -61283,7 +61124,7 @@
-
+
@@ -61318,6 +61159,7 @@
+
@@ -61333,7 +61175,7 @@
-
+
@@ -61346,7 +61188,6 @@
-
@@ -61368,7 +61209,7 @@
-
+
@@ -61392,7 +61233,7 @@
-
+
@@ -61400,7 +61241,6 @@
-
@@ -61410,6 +61250,7 @@
+
@@ -61432,6 +61273,7 @@
+
@@ -61439,7 +61281,7 @@
-
+
@@ -61455,16 +61297,16 @@
-
+
-
+
@@ -61494,18 +61336,18 @@
-
+
-
+
+
-
-
+
-
+
@@ -61513,16 +61355,16 @@
-
+
-
+
-
+
@@ -61537,18 +61379,17 @@
-
-
-
+
-
+
+
@@ -61576,10 +61417,13 @@
+
+
+
@@ -61590,18 +61434,19 @@
+
-
+
-
+
@@ -61620,7 +61465,7 @@
-
+
@@ -61635,13 +61480,13 @@
-
+
@@ -61656,11 +61501,12 @@
+
-
+
-
+
@@ -61672,7 +61518,7 @@
-
+
@@ -61689,6 +61535,7 @@
+
@@ -61699,6 +61546,7 @@
+
@@ -61721,7 +61569,6 @@
-
@@ -61732,9 +61579,8 @@
-
-
-
+
+
@@ -61749,7 +61595,7 @@
-
+
@@ -61781,36 +61627,32 @@
-
-
+
-
+
-
+
-
-
-
+
-
@@ -61819,7 +61661,7 @@
-
+
@@ -61831,8 +61673,6 @@
-
-
@@ -61849,7 +61689,6 @@
-
@@ -61862,7 +61701,7 @@
-
+
@@ -61877,6 +61716,7 @@
+
@@ -61886,7 +61726,7 @@
-
+
@@ -61914,9 +61754,9 @@
-
-
+
+
@@ -61929,29 +61769,30 @@
-
+
-
+
-
+
-
+
+
@@ -61969,7 +61810,8 @@
-
+
+
@@ -61980,7 +61822,7 @@
-
+
@@ -61992,7 +61834,7 @@
-
+
@@ -62003,7 +61845,6 @@
-
@@ -62011,19 +61852,19 @@
-
+
+
-
+
-
@@ -62042,7 +61883,6 @@
-
@@ -62050,11 +61890,11 @@
+
-
-
+
@@ -62069,37 +61909,38 @@
-
+
+
-
-
+
+
-
+
-
-
+
+
@@ -62110,7 +61951,7 @@
-
+
@@ -62122,28 +61963,28 @@
+
-
+
+
-
+
-
-
@@ -62160,14 +62001,15 @@
-
+
+
@@ -62186,26 +62028,24 @@
-
+
-
-
+
-
+
-
-
-
+
+
@@ -62223,6 +62063,7 @@
+
@@ -62230,10 +62071,10 @@
+
-
+
-
@@ -62258,7 +62099,7 @@
-
+
@@ -62280,10 +62121,10 @@
-
+
-
+
@@ -62291,7 +62132,7 @@
-
+
@@ -62307,7 +62148,6 @@
-
@@ -62323,15 +62163,15 @@
-
+
-
+
@@ -62367,7 +62207,6 @@
-
@@ -62377,7 +62216,6 @@
-
@@ -62407,11 +62245,10 @@
-
-
+
-
+
@@ -62427,7 +62264,7 @@
-
+
@@ -62437,20 +62274,22 @@
-
+
+
+
+
-
-
+
@@ -62470,24 +62309,23 @@
-
+
-
+
-
+
-
+
-
-
+
-
+
@@ -62502,24 +62340,24 @@
-
-
-
+
+
-
+
-
+
+
@@ -62527,23 +62365,23 @@
-
+
+
-
@@ -62575,7 +62413,6 @@
-
@@ -62596,7 +62433,7 @@
-
+
@@ -62613,15 +62450,16 @@
-
+
-
+
+
@@ -62629,12 +62467,9 @@
-
-
-
@@ -62643,9 +62478,9 @@
-
+
-
+
@@ -62672,15 +62507,17 @@
-
+
+
+
@@ -62693,7 +62530,6 @@
-
@@ -62708,6 +62544,7 @@
+
@@ -62717,8 +62554,8 @@
-
-
+
+
@@ -62728,7 +62565,7 @@
-
+
@@ -62736,10 +62573,9 @@
-
-
-
-
+
+
+
@@ -62778,26 +62614,28 @@
-
-
+
+
+
-
+
+
@@ -62809,11 +62647,10 @@
-
-
+
@@ -62839,17 +62676,16 @@
-
+
-
+
-
-
+
@@ -62858,6 +62694,7 @@
+
@@ -62873,10 +62710,8 @@
-
+
-
-
@@ -62890,18 +62725,17 @@
-
-
+
-
+
-
+
@@ -62917,7 +62751,9 @@
+
+
@@ -62927,14 +62763,14 @@
-
+
-
+
@@ -62951,9 +62787,10 @@
+
-
+
@@ -62969,7 +62806,6 @@
-
@@ -62985,7 +62821,9 @@
+
+
@@ -62995,7 +62833,7 @@
-
+
@@ -63013,6 +62851,7 @@
+
@@ -63023,9 +62862,8 @@
-
+
-
@@ -63075,10 +62913,12 @@
+
+
@@ -63090,6 +62930,7 @@
+
@@ -63103,23 +62944,22 @@
-
-
+
-
+
@@ -63145,23 +62985,22 @@
+
-
-
+
-
-
+
@@ -63172,28 +63011,26 @@
-
-
+
-
+
-
-
+
@@ -63201,9 +63038,9 @@
+
-
-
+
@@ -63219,10 +63056,10 @@
-
+
@@ -63232,16 +63069,14 @@
-
-
+
-
-
+
@@ -63257,12 +63092,12 @@
-
+
-
+
@@ -63270,7 +63105,7 @@
-
+
@@ -63279,10 +63114,9 @@
-
-
+
@@ -63290,8 +63124,9 @@
+
-
+
@@ -63300,7 +63135,6 @@
-
@@ -63310,7 +63144,6 @@
-
@@ -63325,6 +63158,7 @@
+
@@ -63339,7 +63173,7 @@
-
+
@@ -63365,7 +63199,7 @@
-
+
@@ -63416,7 +63250,7 @@
-
+
@@ -63461,10 +63295,10 @@
-
-
+
+
-
+
@@ -63489,12 +63323,12 @@
-
+
-
+
@@ -63519,7 +63353,6 @@
-
@@ -63544,9 +63377,9 @@
-
+
@@ -63567,7 +63400,7 @@
-
+
@@ -63577,7 +63410,6 @@
-
@@ -63591,10 +63423,8 @@
-
-
@@ -63611,10 +63441,9 @@
-
+
-
@@ -63624,12 +63453,11 @@
+
-
-
@@ -63654,6 +63482,7 @@
+
@@ -63667,36 +63496,32 @@
-
+
-
-
+
-
-
+
-
-
+
-
@@ -63711,18 +63536,18 @@
-
-
+
-
+
+
-
+
@@ -63762,6 +63587,7 @@
+
@@ -63794,17 +63620,19 @@
+
+
-
+
@@ -63812,6 +63640,7 @@
+
@@ -63820,20 +63649,18 @@
-
-
+
-
-
+
@@ -63841,14 +63668,15 @@
+
+
-
@@ -63882,6 +63710,7 @@
+
@@ -63899,6 +63728,7 @@
+
@@ -63910,14 +63740,12 @@
-
-
+
-
@@ -63926,11 +63754,11 @@
-
-
-
+
+
+
-
+
@@ -63944,6 +63772,7 @@
+
@@ -63985,7 +63814,6 @@
-
@@ -63999,6 +63827,7 @@
+
@@ -64026,7 +63855,7 @@
-
+
@@ -64034,9 +63863,10 @@
-
+
-
+
+
@@ -64045,17 +63875,17 @@
-
+
-
+
-
+
@@ -64115,7 +63945,7 @@
-
+
@@ -64128,7 +63958,7 @@
-
+
@@ -64139,9 +63969,9 @@
-
+
-
+
@@ -64155,19 +63985,20 @@
-
+
+
-
+
@@ -64180,7 +64011,6 @@
-
@@ -64199,7 +64029,6 @@
-
@@ -64216,6 +64045,7 @@
+
@@ -64225,7 +64055,6 @@
-
@@ -64233,7 +64062,7 @@
-
+
@@ -64249,7 +64078,7 @@
-
+
@@ -64269,8 +64098,6 @@
-
-
@@ -64281,18 +64108,19 @@
-
-
+
+
-
+
+
@@ -64300,12 +64128,12 @@
+
-
@@ -64316,7 +64144,6 @@
-
@@ -64325,7 +64152,9 @@
+
+
@@ -64338,7 +64167,7 @@
-
+
@@ -64350,7 +64179,7 @@
-
+
@@ -64367,7 +64196,7 @@
-
+
@@ -64375,6 +64204,7 @@
+
@@ -64400,6 +64230,7 @@
+
@@ -64421,13 +64252,13 @@
+
-
+
-
@@ -64443,6 +64274,7 @@
+
@@ -64458,11 +64290,10 @@
-
+
-
-
+
@@ -64488,10 +64319,10 @@
-
+
@@ -64503,11 +64334,10 @@
-
+
-
@@ -64522,6 +64352,7 @@
+
@@ -64529,7 +64360,6 @@
-
@@ -64553,29 +64383,33 @@
-
+
-
+
+
+
+
+
@@ -64599,8 +64433,7 @@
-
-
+
@@ -64613,6 +64446,7 @@
+
@@ -64621,14 +64455,14 @@
-
+
-
+
-
+
@@ -64647,7 +64481,6 @@
-
@@ -64656,7 +64489,7 @@
-
+
@@ -64668,10 +64501,10 @@
-
+
-
+
@@ -64689,13 +64522,13 @@
-
+
-
+
@@ -64704,13 +64537,13 @@
-
-
-
+
+
+
@@ -64731,29 +64564,29 @@
+
-
+
-
+
-
-
+
-
+
@@ -64764,14 +64597,13 @@
-
-
+
-
+
@@ -64786,11 +64618,12 @@
+
-
+
@@ -64803,7 +64636,7 @@
-
+
@@ -64814,19 +64647,19 @@
-
+
-
+
-
+
@@ -64840,7 +64673,7 @@
-
+
@@ -64862,8 +64695,9 @@
-
+
+
@@ -64877,6 +64711,7 @@
+
@@ -64908,14 +64743,14 @@
+
+
-
-
@@ -64923,10 +64758,10 @@
-
+
-
+
@@ -64935,7 +64770,7 @@
-
+
@@ -64959,8 +64794,8 @@
-
-
+
+
@@ -64987,7 +64822,7 @@
-
+
@@ -64999,8 +64834,10 @@
+
+
@@ -65012,7 +64849,7 @@
-
+
@@ -65020,7 +64857,6 @@
-
@@ -65028,7 +64864,6 @@
-
@@ -65039,14 +64874,15 @@
+
-
+
@@ -65055,29 +64891,29 @@
-
+
-
+
+
-
-
+
@@ -65095,7 +64931,7 @@
-
+
@@ -65112,7 +64948,7 @@
-
+
@@ -65121,11 +64957,12 @@
-
+
+
+
-
@@ -65133,6 +64970,7 @@
+
@@ -65143,7 +64981,7 @@
-
+
@@ -65166,22 +65004,20 @@
-
-
+
+
-
-
+
-
+
-
@@ -65191,30 +65027,29 @@
-
+
+
+
-
+
-
-
-
-
+
@@ -65228,7 +65063,7 @@
-
+
@@ -65267,15 +65102,14 @@
-
-
-
+
+
@@ -65286,11 +65120,9 @@
-
+
-
-
@@ -65305,9 +65137,10 @@
-
+
+
-
+
@@ -65317,10 +65150,10 @@
-
+
-
+
@@ -65328,15 +65161,15 @@
-
-
-
+
+
+
-
+
@@ -65385,13 +65218,12 @@
-
+
-
@@ -65407,18 +65239,18 @@
-
-
+
+
@@ -65426,18 +65258,19 @@
-
-
-
+
+
+
+
-
+
@@ -65449,15 +65282,17 @@
-
+
+
-
+
+
@@ -65465,10 +65300,10 @@
-
+
-
+
@@ -65486,6 +65321,7 @@
+
@@ -65493,14 +65329,13 @@
-
+
-
@@ -65514,18 +65349,19 @@
-
+
-
+
-
+
+
-
+
@@ -65534,9 +65370,8 @@
-
-
+
@@ -65548,14 +65383,13 @@
-
+
-
+
-
-
+
@@ -65573,11 +65407,12 @@
-
+
-
+
+
@@ -65585,8 +65420,6 @@
-
-
@@ -65607,14 +65440,13 @@
-
-
+
-
+
-
+
@@ -65636,12 +65468,11 @@
-
+
-
+
-
@@ -65651,9 +65482,8 @@
-
-
+
@@ -65673,23 +65503,23 @@
-
+
+
-
+
-
@@ -65706,22 +65536,22 @@
-
+
-
-
+
-
+
-
+
-
+
+
@@ -65729,6 +65559,7 @@
+
@@ -65740,21 +65571,20 @@
-
+
-
+
-
-
+
@@ -65773,7 +65603,7 @@
-
+
@@ -65786,6 +65616,7 @@
+
@@ -65809,9 +65640,7 @@
-
-
@@ -65821,6 +65650,7 @@
+
@@ -65829,9 +65659,9 @@
-
+
-
+
@@ -65842,7 +65672,7 @@
-
+
@@ -65853,7 +65683,7 @@
-
+
@@ -65871,18 +65701,18 @@
-
+
-
+
@@ -65891,15 +65721,17 @@
+
+
-
+
@@ -65911,8 +65743,8 @@
-
-
+
+
@@ -65933,20 +65765,19 @@
-
+
+
-
-
@@ -65956,7 +65787,7 @@
-
+
@@ -65964,10 +65795,11 @@
-
+
+
@@ -65977,9 +65809,11 @@
+
+
@@ -65989,12 +65823,12 @@
-
+
-
+
@@ -66005,7 +65839,7 @@
-
+
@@ -66025,7 +65859,6 @@
-
@@ -66041,7 +65874,7 @@
-
+
@@ -66051,7 +65884,6 @@
-
@@ -66059,13 +65891,11 @@
-
-
@@ -66078,7 +65908,7 @@
-
+
@@ -66088,7 +65918,7 @@
-
+
@@ -66110,15 +65940,16 @@
+
+
-
-
+
-
+
@@ -66138,31 +65969,43 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -66175,6 +66018,8 @@
+
+
@@ -66182,23 +66027,26 @@
-
+
+
+
+
+
-
+
-
-
+
@@ -66210,13 +66058,12 @@
-
+
-
@@ -66230,31 +66077,28 @@
-
-
+
-
-
-
+
-
+
-
+
@@ -66264,26 +66108,23 @@
+
-
+
+
-
-
-
-
+
-
+
-
-
@@ -66295,27 +66136,35 @@
+
+
+
+
+
+
-
+
+
-
+
+
@@ -66326,19 +66175,21 @@
-
+
+
+
+
-
+
-
@@ -66348,8 +66199,6 @@
-
-
@@ -66361,45 +66210,49 @@
-
-
-
-
+
-
+
+
+
-
+
+
+
+
+
-
+
+
@@ -66407,13 +66260,12 @@
-
+
-
@@ -66425,7 +66277,6 @@
-
@@ -66443,6 +66294,7 @@
+
@@ -66451,13 +66303,9 @@
-
+
-
-
-
-
@@ -66467,59 +66315,64 @@
-
+
+
+
-
+
+
-
+
-
+
+
-
+
-
+
+
+
-
+
-
@@ -66530,19 +66383,22 @@
+
-
+
+
+
@@ -66555,7 +66411,11 @@
+
+
+
+
@@ -66565,39 +66425,36 @@
-
+
-
+
+
-
-
+
-
-
-
+
-
-
-
-
+
+
+
@@ -66607,30 +66464,26 @@
-
-
-
+
-
-
+
-
-
+
@@ -66638,7 +66491,7 @@
-
+
@@ -66647,15 +66500,18 @@
+
+
+
@@ -66668,25 +66524,26 @@
-
+
+
-
+
-
+
@@ -66695,37 +66552,44 @@
+
+
+
-
+
+
-
+
-
+
-
-
+
+
+
+
+
@@ -66733,30 +66597,26 @@
-
-
+
+
-
-
-
-
-
+
@@ -66767,35 +66627,37 @@
-
+
-
+
+
+
+
-
-
+
@@ -66803,17 +66665,17 @@
+
-
-
+
@@ -66821,28 +66683,23 @@
-
-
-
-
+
-
-
-
+
+
-
@@ -66853,6 +66710,9 @@
+
+
+
@@ -66863,26 +66723,29 @@
+
-
+
+
-
+
-
+
+
@@ -66892,10 +66755,9 @@
-
+
-
@@ -66903,14 +66765,15 @@
-
+
-
-
+
+
+
@@ -66925,12 +66788,13 @@
+
-
+
-
+
@@ -66938,50 +66802,50 @@
-
-
-
-
+
-
-
+
+
-
-
+
-
-
+
+
+
+
+
+
@@ -66990,21 +66854,16 @@
-
-
-
-
-
-
+
@@ -67012,14 +66871,14 @@
-
-
+
+
@@ -67030,14 +66889,17 @@
+
+
+
-
+
@@ -67045,6 +66907,7 @@
+
@@ -67053,69 +66916,76 @@
+
-
+
+
-
+
-
-
+
+
+
+
-
-
-
+
+
+
+
-
-
+
+
+
+
@@ -67125,19 +66995,20 @@
+
-
-
+
+
@@ -67149,14 +67020,13 @@
-
+
+
-
-
-
+
@@ -67165,7 +67035,6 @@
-
@@ -67178,7 +67047,6 @@
-
@@ -67188,8 +67056,6 @@
-
-
@@ -67199,7 +67065,6 @@
-
@@ -67207,45 +67072,43 @@
-
-
-
-
-
+
+
+
+
-
-
+
-
-
+
+
-
-
+
+
@@ -67254,18 +67117,19 @@
-
-
+
+
+
@@ -67277,37 +67141,37 @@
+
+
+
+
+
-
-
-
+
-
-
-
@@ -67320,28 +67184,28 @@
+
+
-
-
-
-
+
-
+
-
-
+
+
+
@@ -67349,49 +67213,47 @@
+
+
-
+
-
+
-
-
-
-
-
+
+
-
-
+
-
+
@@ -67407,7 +67269,6 @@
-
@@ -67422,8 +67283,10 @@
+
+
@@ -67432,10 +67295,9 @@
-
+
-
@@ -67443,12 +67305,13 @@
-
+
+
@@ -67457,7 +67320,7 @@
-
+
@@ -67466,6 +67329,7 @@
+
@@ -67478,39 +67342,32 @@
-
-
-
-
-
+
+
-
-
-
-
-
+
@@ -67521,24 +67378,25 @@
+
+
+
+
-
-
-
@@ -67547,37 +67405,29 @@
-
-
-
-
-
+
-
-
-
-
-
-
+
+
-
+
@@ -67592,27 +67442,31 @@
-
-
+
+
+
+
+
+
@@ -67622,28 +67476,20 @@
-
-
-
-
+
-
-
-
-
-
@@ -67651,51 +67497,53 @@
+
+
-
+
+
-
+
-
-
-
+
+
@@ -67708,10 +67556,7 @@
-
-
-
@@ -67719,57 +67564,51 @@
+
-
-
+
-
-
+
-
-
+
-
-
-
-
+
+
-
-
+
-
@@ -67777,26 +67616,27 @@
+
-
+
-
+
+
-
@@ -67806,25 +67646,30 @@
+
+
+
+
+
+
-
+
-
@@ -67836,41 +67681,36 @@
+
-
-
+
-
-
-
-
-
-
+
@@ -67880,49 +67720,43 @@
-
-
-
-
-
-
-
+
+
-
-
+
+
+
-
+
-
+
-
-
-
+
@@ -67933,73 +67767,75 @@
+
-
-
+
-
+
+
+
+
-
-
+
+
+
+
-
-
-
+
-
-
+
-
+
+
-
+
-
-
+
-
-
+
+
-
+
@@ -68015,32 +67851,31 @@
-
-
+
+
+
+
-
-
-
@@ -68053,34 +67888,34 @@
+
+
+
-
-
+
+
-
-
+
-
+
-
-
@@ -68095,59 +67930,57 @@
-
+
-
-
+
+
-
-
+
-
+
+
-
-
-
+
-
-
+
+
@@ -68155,37 +67988,31 @@
-
-
-
-
+
-
-
-
-
+
@@ -68196,7 +68023,6 @@
-
@@ -68206,6 +68032,7 @@
+
@@ -68213,25 +68040,24 @@
-
+
-
-
-
+
+
@@ -68241,40 +68067,44 @@
+
+
-
+
+
-
-
+
-
+
+
-
-
+
+
+
+
-
-
+
@@ -68287,23 +68117,28 @@
-
+
+
+
-
+
+
+
+
@@ -68318,78 +68153,75 @@
+
+
-
-
+
-
-
-
-
-
-
-
-
+
+
+
+
-
+
-
-
+
-
-
+
+
+
@@ -68403,38 +68235,39 @@
-
+
+
+
-
+
-
-
+
@@ -68442,12 +68275,12 @@
-
+
-
+
@@ -68457,34 +68290,34 @@
+
-
-
+
+
-
-
+
+
-
@@ -68500,17 +68333,12 @@
-
+
-
-
-
-
-
@@ -68523,17 +68351,27 @@
+
+
+
-
+
+
+
+
+
+
+
+
@@ -68541,16 +68379,17 @@
-
-
+
+
+
@@ -68562,19 +68401,24 @@
+
+
-
+
+
+
+
@@ -68582,55 +68426,52 @@
-
-
+
+
+
-
-
-
+
-
-
+
-
+
-
-
+
@@ -68640,34 +68481,29 @@
-
-
+
-
-
-
-
+
-
+
-
-
-
+
+
+
-
@@ -68676,6 +68512,7 @@
+
@@ -68685,40 +68522,40 @@
-
+
+
-
-
-
+
+
-
+
+
-
+
-
-
-
+
+
@@ -68732,7 +68569,6 @@
-
@@ -68750,39 +68586,39 @@
+
-
-
+
-
+
+
-
+
-
+
-
-
+
@@ -68791,27 +68627,25 @@
-
-
-
+
+
-
-
+
@@ -68825,36 +68659,35 @@
+
-
-
+
+
+
-
-
+
-
-
+
+
-
-
@@ -68864,12 +68697,9 @@
-
-
+
-
-
-
+
@@ -68878,54 +68708,55 @@
-
+
-
-
+
-
-
+
+
-
-
-
+
-
+
+
+
+
+
-
+
@@ -68933,82 +68764,87 @@
+
+
-
+
+
+
-
+
+
+
-
+
+
-
+
-
+
-
-
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -69025,21 +68861,21 @@
-
-
+
-
+
+
-
+
@@ -69047,9 +68883,11 @@
+
+
@@ -69057,32 +68895,30 @@
-
-
-
+
+
-
+
-
+
-
@@ -69090,6 +68926,7 @@
+
@@ -69098,14 +68935,14 @@
+
-
+
-
-
+
@@ -69115,14 +68952,12 @@
-
-
+
-
@@ -69131,9 +68966,7 @@
-
-
@@ -69151,16 +68984,18 @@
-
+
+
+
-
+
diff --git a/Engine/Build/PhysXBuild.xml b/Engine/Build/PhysXBuild.xml
index 29c383a0d851..c5b417832f50 100644
--- a/Engine/Build/PhysXBuild.xml
+++ b/Engine/Build/PhysXBuild.xml
@@ -7,6 +7,7 @@
+
@@ -35,6 +36,7 @@
+
diff --git a/Engine/Config/Android/AndroidEngine.ini b/Engine/Config/Android/AndroidEngine.ini
index d2ba6f693052..e46ef8cd8aa8 100644
--- a/Engine/Config/Android/AndroidEngine.ini
+++ b/Engine/Config/Android/AndroidEngine.ini
@@ -15,13 +15,15 @@ AudioDeviceModuleName=AndroidAudio
; Defining below allows switching to audio mixer using -audiomixer commandline
AudioMixerModuleName=AudioMixerAndroid
; Defines a platform-specific volume headroom (in dB) for audio to provide better platform consistency with respect to volume levels.
-PlatformHeadroomDB=0
+PlatformHeadroomDB=-6
[PlatformMemoryBuckets]
LargestMemoryBucket_MinGB=8
LargerMemoryBucket_MinGB=6
DefaultMemoryBucket_MinGB=4
SmallerMemoryBucket_MinGB=3
+ ; for now, we require 3gb
+SmallestMemoryBucket_MinGB=3
[DeviceProfileManager]
@@ -32,6 +34,8 @@ DefaultProviderName=AndroidAdvertising
[OnlineSubsystem]
DefaultPlatformService=GooglePlay
+
+[OnlineSubsystemMcp]
bUseMCPIdentityForPlayerName=true
[SlateRenderer]
@@ -66,5 +70,6 @@ DefaultPlatformService=AndroidLocalNotification
[ConsoleVariables]
Slate.CacheRenderData=0
+r.VSync=1
;GalaxyS6Edge=577
diff --git a/Engine/Config/Android/BaseAndroidEngine.ini b/Engine/Config/Android/BaseAndroidEngine.ini
new file mode 100644
index 000000000000..08bb726e6471
--- /dev/null
+++ b/Engine/Config/Android/BaseAndroidEngine.ini
@@ -0,0 +1,2 @@
+[OnlineSubsystem]
+NativePlatformService=GooglePlay
\ No newline at end of file
diff --git a/Engine/Config/BaseDeviceProfiles.ini b/Engine/Config/BaseDeviceProfiles.ini
index 53010bfd86e6..ed342ae32a85 100644
--- a/Engine/Config/BaseDeviceProfiles.ini
+++ b/Engine/Config/BaseDeviceProfiles.ini
@@ -58,7 +58,11 @@
+DeviceProfileNameAndTypes=Android_Adreno330_Ver53,Android
+DeviceProfileNameAndTypes=Android_Adreno4xx_Nexus6,Android
+DeviceProfileNameAndTypes=Android_Adreno4xx,Android
++DeviceProfileNameAndTypes=Android_Adreno5xx,Android
++DeviceProfileNameAndTypes=Android_Adreno6xx,Android
+DeviceProfileNameAndTypes=Android_PowerVR54x,Android
++DeviceProfileNameAndTypes=Android_PowerVRLow,Android
++DeviceProfileNameAndTypes=Android_PowerVRMid,Android
+DeviceProfileNameAndTypes=Android_TegraK1,Android
+DeviceProfileNameAndTypes=Android_Tegra4,Android
+DeviceProfileNameAndTypes=Android_IntelHD,Android
@@ -274,6 +278,7 @@ BaseProfileName=iPhone7Plus
[iPhoneX DeviceProfile]
DeviceType=IOS
BaseProfileName=iPhone8
++CVars=r.CustomUnsafeZones="(L:free[0,-15][812,15]);(P:fixed[83,0][206,30])"
[iPadPro DeviceProfile]
DeviceType=IOS
@@ -322,6 +327,8 @@ BaseProfileName=IPadPro97
[/Script/AndroidDeviceProfileSelector.AndroidDeviceProfileMatchingRules]
MatchProfile=(Profile="Android_PowerVR54x",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="PowerVR SGX 54[0-9]")))
++MatchProfile=(Profile="Android_PowerVRMid",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="PowerVR"),(SourceType=SRC_GlVersion,CompareType=CMP_Regex,MatchString="^OpenGL ES 3\\.")))
++MatchProfile=(Profile="Android_PowerVRLow",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="PowerVR")))
+MatchProfile=(Profile="Android_Adreno2xx",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="Adreno \\(TM\\) 2[0-9][0-9]")))
+MatchProfile=(Profile="Android_Adreno320",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Equal,MatchString="Adreno (TM) 320")))
+MatchProfile=(Profile="Android_Adreno330_Ver53",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Equal,MatchString="Adreno (TM) 330"),(SourceType=SRC_GlVersion,CompareType=CMP_Regex,MatchString="ES 3\\.0 V@([0-9]+)"),(SourceType=SRC_PreviousRegexMatch,CompareType=CMP_GreaterEqual,MatchString="53")))
@@ -330,6 +337,7 @@ MatchProfile=(Profile="Android_PowerVR54x",Match=((SourceType=SRC_GpuFamily,Comp
+MatchProfile=(Profile="Android_Adreno4xx",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="Adreno \\(TM\\) 4[0-9][0-9]")))
+MatchProfile=(Profile="Android_Adreno51x",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="Adreno \\(TM\\) 51[0-9]")))
+MatchProfile=(Profile="Android_Adreno5xx",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="Adreno \\(TM\\) 5[0-9][0-9]")))
++MatchProfile=(Profile="Android_Adreno6xx",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Regex,MatchString="Adreno \\(TM\\) 6[0-9][0-9]")))
+MatchProfile=(Profile="Android_TegraK1",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Equal,MatchString="NVIDIA Tegra"),(SourceType=SRC_GlVersion,CompareType=CMP_Regex,MatchString="^OpenGL ES 3\\.")))
+MatchProfile=(Profile="Android_Tegra4",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Equal,MatchString="NVIDIA Tegra"),(SourceType=SRC_GlVersion,CompareType=CMP_Regex,MatchString="^OpenGL ES 2\\.")))
+MatchProfile=(Profile="Android_IntelHD_ES3",Match=((SourceType=SRC_GpuFamily,CompareType=CMP_Equal,MatchString="Intel(R) HD Graphics"),(SourceType=SRC_GlVersion,CompareType=CMP_Regex,MatchString="^OpenGL ES 3\\.")))
@@ -423,6 +431,12 @@ BaseProfileName=Android_High
[Android_Adreno5xx DeviceProfile]
DeviceType=Android
BaseProfileName=Android_High
++CVars=r.DisjointTimerQueries=1
+
+[Android_Adreno6xx DeviceProfile]
+DeviceType=Android
+BaseProfileName=Android_High
++CVars=r.DisjointTimerQueries=1
[Android_Adreno4xx DeviceProfile]
DeviceType=Android
@@ -436,6 +450,19 @@ BaseProfileName=Android_Adreno4xx
DeviceType=Android
BaseProfileName=Android_Mid
+CVars=r.Mobile.ForceDepthResolve=1
++CVars=r.Android.DisableASTCSupport=1
+
+[Android_PowerVRMid DeviceProfile]
+DeviceType=Android
+BaseProfileName=Android_Mid
++CVars=r.Mobile.ForceDepthResolve=1
++CVars=r.Android.DisableASTCSupport=1
+
+[Android_PowerVRLow DeviceProfile]
+DeviceType=Android
+BaseProfileName=Android_Low
++CVars=r.Mobile.ForceDepthResolve=1
++CVars=r.Android.DisableASTCSupport=1
[Android_IntelHD DeviceProfile]
DeviceType=Android
diff --git a/Engine/Config/BaseEditor.ini b/Engine/Config/BaseEditor.ini
index 41a13fbc8a2a..8187608624f0 100644
--- a/Engine/Config/BaseEditor.ini
+++ b/Engine/Config/BaseEditor.ini
@@ -40,6 +40,7 @@ MaxNumberOfLogLines=2000
+RenderableThumbnailTypes=(ClassNeedingThumbnailName="/Script/Engine.SlateBrushAsset",RendererClassName="/Script/UnrealEd.SlateBrushThumbnailRenderer")
+RenderableThumbnailTypes=(ClassNeedingThumbnailName="/Script/Engine.SubsurfaceProfile",RendererClassName="/Script/UnrealEd.SubsurfaceProfileRenderer")
+RenderableThumbnailTypes=(ClassNeedingThumbnailName="/Script/Engine.PhysicsAsset",RendererClassName="/Script/UnrealEd.PhysicsAssetThumbnailRenderer")
++RenderableThumbnailTypes=(ClassNeedingThumbnailName="/Script/Engine.CurveLinearColor",RendererClassName="/Script/UnrealEd.CurveLinearColorThumbnailRenderer")
[/Script/UnrealEd.DefaultSizedThumbnailRenderer]
DefaultSizeX=512
diff --git a/Engine/Config/BaseEditorPerProjectUserSettings.ini b/Engine/Config/BaseEditorPerProjectUserSettings.ini
index a2a68570a85b..5634572f5ed9 100644
--- a/Engine/Config/BaseEditorPerProjectUserSettings.ini
+++ b/Engine/Config/BaseEditorPerProjectUserSettings.ini
@@ -71,19 +71,21 @@ MapSkeletalMotionToRoot=False
[/Script/EditorStyle.EditorStyleSettings]
; Applies a color vision deficiency filter to the entire editor
-ColorVisionDeficiencyType=CVD_NormalVision
+ColorVisionDeficiencyPreviewType=NormalVision
+ColorVisionDeficiencySeverity=3
+
SelectionColor=(R=0.728f,G=0.364f,B=0.003f,A=1.000000)
PressedSelectionColor=(R=0.701f,G=0.225f,B=0.003f,A=1.000000)
InactiveSelectionColor=(R=0.25f,G=0.25f,B=0.25f,A=1.000000)
SelectorColor=(R=0.701f,G=0.225f,B=0.003f,A=1.000000)
-LogBackgroundColor=(R=0.047059,G=0.047059,B=0.047059,A=1.000000)
-LogSelectionBackgroundColor=(R=0.132868,G=0.132868,B=0.132868,A=1.000000)
+LogBackgroundColor=(R=0.015996,G=0.015996,B=0.015996,A=1.000000)
+LogSelectionBackgroundColor=(R=0.008023,G=0.008023,B=0.008023,A=1.000000)
LogNormalColor=(R=0.72,G=0.72,B=0.72,A=1.000000)
LogCommandColor=(R=0.033105,G=0.723055,B=0.033105,A=1.000000)
-LogWarningColor=(R=0.496933,G=0.496933,B=0.057805,A=1.000000)
-LogErrorColor=(R=0.723055,G=0.000000,B=0.000000,A=1.000000)
+LogWarningColor=(R=0.921875,G=0.691406,B=0.000000,A=1.000000)
+LogErrorColor=(R=1.000000,G=0.052083,B=0.060957,A=1.000000)
LogFontSize=9
; If true, all toolbars will use small icons without labels
@@ -216,50 +218,64 @@ LastExecutedLaunchModeType=LaunchMode_OnDevice
LastExecutedLaunchPlatform=
; common screen resolutions for laptops
-+LaptopScreenResolutions=(Description="Apple MacBook Air 11",Width=1366,Height=768,AspectRatio="16:9")
-+LaptopScreenResolutions=(Description="Apple MacBook Air 13\"",Width=1440,Height=900,AspectRatio="16:10")
-+LaptopScreenResolutions=(Description="Apple MacBook Pro 13\"",Width=1280,Height=800,AspectRatio="16:10")
-+LaptopScreenResolutions=(Description="Apple MacBook Pro 13\" (Retina)",Width=2560,Height=1600,AspectRatio="16:10")
-+LaptopScreenResolutions=(Description="Apple MacBook Pro 15\"",Width=1440,Height=900,AspectRatio="16:10")
-+LaptopScreenResolutions=(Description="Apple MacBook Pro 15\" (Retina)",Width=2880,Height=1800,AspectRatio="16:10")
-+LaptopScreenResolutions=(Description="Generic 14-15.6\" Notebook",Width=1366,Height=768,AspectRatio="16:9")
++LaptopScreenResolutions=(Description="Apple MacBook Air 11",Width=1366,Height=768,AspectRatio="16:9",bCanSwapAspectRatio=false)
++LaptopScreenResolutions=(Description="Apple MacBook Air 13\"",Width=1440,Height=900,AspectRatio="16:10",bCanSwapAspectRatio=false)
++LaptopScreenResolutions=(Description="Apple MacBook Pro 13\"",Width=1280,Height=800,AspectRatio="16:10",bCanSwapAspectRatio=false)
++LaptopScreenResolutions=(Description="Apple MacBook Pro 13\" (Retina)",Width=2560,Height=1600,AspectRatio="16:10",bCanSwapAspectRatio=false)
++LaptopScreenResolutions=(Description="Apple MacBook Pro 15\"",Width=1440,Height=900,AspectRatio="16:10",bCanSwapAspectRatio=false)
++LaptopScreenResolutions=(Description="Apple MacBook Pro 15\" (Retina)",Width=2880,Height=1800,AspectRatio="16:10",bCanSwapAspectRatio=false)
++LaptopScreenResolutions=(Description="Generic 14-15.6\" Notebook",Width=1366,Height=768,AspectRatio="16:9",bCanSwapAspectRatio=false)
; common screen resolutions for desktop monitors
-+MonitorScreenResolutions=(Description="19\" monitor",Width=1440,Height=900,AspectRatio="16:10")
-+MonitorScreenResolutions=(Description="20\" monitor",Width=1600,Height=900,AspectRatio="16:9")
-+MonitorScreenResolutions=(Description="22\" monitor",Width=1680,Height=1050,AspectRatio="16:10")
-+MonitorScreenResolutions=(Description="21.5-24\" monitor",Width=1920,Height=1080,AspectRatio="16:9")
-+MonitorScreenResolutions=(Description="27\" monitor",Width=2560,Height=1440,AspectRatio="16:9")
++MonitorScreenResolutions=(Description="19\" monitor",Width=1440,Height=900,AspectRatio="16:10",bCanSwapAspectRatio=false)
++MonitorScreenResolutions=(Description="20\" monitor",Width=1600,Height=900,AspectRatio="16:9",bCanSwapAspectRatio=false)
++MonitorScreenResolutions=(Description="22\" monitor",Width=1680,Height=1050,AspectRatio="16:10",bCanSwapAspectRatio=false)
++MonitorScreenResolutions=(Description="21.5-24\" monitor",Width=1920,Height=1080,AspectRatio="16:9",bCanSwapAspectRatio=false)
++MonitorScreenResolutions=(Description="27\" monitor",Width=2560,Height=1440,AspectRatio="16:9",bCanSwapAspectRatio=false)
; common screen resolutions for mobile phones
-+PhoneScreenResolutions=(Description="Apple iPhone 4, 4S, iTouch 4 (Portrait)",Width=640,Height=960,AspectRatio="2:3")
-+PhoneScreenResolutions=(Description="Apple iPhone 4, 4S, iTouch 4 (Landscape)",Width=960,Height=640,AspectRatio="3:2")
-+PhoneScreenResolutions=(Description="Apple iPhone 5, 5S, iTouch 5 (Portrait)",Width=640,Height=1136,AspectRatio="~9:16")
-+PhoneScreenResolutions=(Description="Apple iPhone 5, 5S, iTouch 5 (Landscape)",Width=1136,Height=640,AspectRatio="~16:9")
-+PhoneScreenResolutions=(Description="Apple iPhone 6 (Portrait)",Width=750,Height=1334,AspectRatio="16:9")
-+PhoneScreenResolutions=(Description="Apple iPhone 6 (Landscape)",Width=1334,Height=750,AspectRatio="16:9")
-+PhoneScreenResolutions=(Description="Apple iPhone 6+ (Portrait)",Width=1080,Height=1920,AspectRatio="16:9")
-+PhoneScreenResolutions=(Description="Apple iPhone 6+ (Landscape)",Width=1920,Height=1080,AspectRatio="16:9")
-+PhoneScreenResolutions=(Description="HTC One (Portrait)",Width=1080,Height=1920,AspectRatio="9:16")
-+PhoneScreenResolutions=(Description="HTC One (Landscape)",Width=1920,Height=1080,AspectRatio="16:9")
-+PhoneScreenResolutions=(Description="Samsung Galaxy S4 (Portrait)",Width=1080,Height=1920,AspectRatio="9:16")
-+PhoneScreenResolutions=(Description="Samsung Galaxy S4 (Landscape)",Width=1920,Height=1080,AspectRatio="16:9")
++PhoneScreenResolutions=(Description="Apple iPhone 5S",Width=320,Height=568,AspectRatio="~16:9",bCanSwapAspectRatio=true,ProfileName="iPhone5S")
++PhoneScreenResolutions=(Description="Apple iPhone 6",Width=375,Height=667,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="iPhone6")
++PhoneScreenResolutions=(Description="Apple iPhone 6+",Width=414,Height=736,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="iPhone6Plus")
++PhoneScreenResolutions=(Description="Apple iPhone 6S",Width=375,Height=667,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="iPhone6S")
++PhoneScreenResolutions=(Description="Apple iPhone 6S+",Width=414,Height=736,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="iPhone6SPlus")
++PhoneScreenResolutions=(Description="Apple iPhone 7",Width=375,Height=667,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="iPhone7")
++PhoneScreenResolutions=(Description="Apple iPhone 7+",Width=414,Height=736,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="iPhone7Plus")
++PhoneScreenResolutions=(Description="Apple iPhone 8",Width=375,Height=667,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="iPhone8")
++PhoneScreenResolutions=(Description="Apple iPhone 8+",Width=414,Height=736,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="iPhone8Plus")
++PhoneScreenResolutions=(Description="Apple iPhone X",Width=375,Height=812,AspectRatio="19.5:9",bCanSwapAspectRatio=true,ProfileName="iPhoneX")
++PhoneScreenResolutions=(Description="HTC One",Width=1080,Height=1920,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_High")
++PhoneScreenResolutions=(Description="Samsung Galaxy S4",Width=1080,Height=1920,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_Low")
++PhoneScreenResolutions=(Description="Samsung Galaxy S6",Width=1440,Height=2560,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_Mali_T7xx")
++PhoneScreenResolutions=(Description="Samsung Galaxy S7",Width=1440,Height=2560,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_High")
++PhoneScreenResolutions=(Description="Samsung Galaxy S8 (Mali)",Width=1080,Height=2220,AspectRatio="18.5:9",bCanSwapAspectRatio=true,ProfileName="Android_Mali_G71")
++PhoneScreenResolutions=(Description="Samsung Galaxy S8 (Adreno)",Width=1080,Height=2220,AspectRatio="18.5:9",bCanSwapAspectRatio=true,ProfileName="Android_Adreno5xx")
++PhoneScreenResolutions=(Description="Samsung Galaxy S9 (Mali)",Width=1440,Height=2960,AspectRatio="18.5:9",bCanSwapAspectRatio=true,ProfileName="Android_High")
++PhoneScreenResolutions=(Description="Samsung Galaxy S9 (Adreno)",Width=1440,Height=2960,AspectRatio="18.5:9",bCanSwapAspectRatio=true,ProfileName="Android_High")
++PhoneScreenResolutions=(Description="Google Pixel",Width=1080,Height=1920,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_Mid")
++PhoneScreenResolutions=(Description="Google Pixel XL",Width=1080,Height=1920,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_Mid")
++PhoneScreenResolutions=(Description="Google Pixel 2",Width=1080,Height=1920,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_Mid")
++PhoneScreenResolutions=(Description="Google Pixel 2 XL",Width=1080,Height=1920,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_Mid")
++PhoneScreenResolutions=(Description="Razer Phone",Width=1080,Height=1920,AspectRatio="16:9",bCanSwapAspectRatio=true,ProfileName="Android_Mid")
; common screen resolutions for tablet devices
-+TabletScreenResolutions=(Description="Apple iPad 2, iPad Mini (Portrait)",Width=768,Height=1024,AspectRatio="~3:4")
-+TabletScreenResolutions=(Description="Apple iPad 2, iPad Mini (Landscape)",Width=1024,Height=768,AspectRatio="~4:3")
-+TabletScreenResolutions=(Description="Apple iPad 3, 4, Air (Portrait)",Width=1536,Height=2048,AspectRatio="3:4")
-+TabletScreenResolutions=(Description="Apple iPad 3, 4, Air (Landscape)",Width=2048,Height=1536,AspectRatio="4:3")
-+TabletScreenResolutions=(Description="Microsoft Surface RT (Portrait)",Width=768,Height=1366,AspectRatio="9:16")
-+TabletScreenResolutions=(Description="Microsoft Surface RT (Landscape)",Width=1366,Height=768,AspectRatio="16:9")
-+TabletScreenResolutions=(Description="Microsoft Surface Pro (Portrait)",Width=1080,Height=1920,AspectRatio="9:16")
-+TabletScreenResolutions=(Description="Microsoft Surface Pro (Landscape)",Width=1920,Height=1080,AspectRatio="16:9")
++TabletScreenResolutions=(Description="iPad Pro 12.9-inch (2nd gen.)",Width=1024,Height=1366,AspectRatio="~3:4",bCanSwapAspectRatio=true,ProfileName="iPadPro2_129")
++TabletScreenResolutions=(Description="iPad Pro 10.5-inch",Width=834,Height=1112,AspectRatio="3:4",bCanSwapAspectRatio=true,ProfileName="iPadPro105")
++TabletScreenResolutions=(Description="iPad Pro 12.9-inch",Width=1024,Height=1366,AspectRatio="3:4",bCanSwapAspectRatio=true,ProfileName="iPadPro129")
++TabletScreenResolutions=(Description="iPad Pro 9.7-inch",Width=768,Height=1024,AspectRatio="3:4",bCanSwapAspectRatio=true,ProfileName="iPadPro97")
++TabletScreenResolutions=(Description="iPad Air 2",Width=768,Height=1024,AspectRatio="3:4",bCanSwapAspectRatio=true,ProfileName="iPadAir2")
++TabletScreenResolutions=(Description="iPad Mini 4",Width=768,Height=1024,AspectRatio="3:4",bCanSwapAspectRatio=true,ProfileName="iPadMini4")
++TabletScreenResolutions=(Description="LG G Pad X 8.0",Width=768,Height=1366,AspectRatio="9:16",bCanSwapAspectRatio=true)
++TabletScreenResolutions=(Description="Asus Zenpad 3s 10",Width=768,Height=1366,AspectRatio="9:16",bCanSwapAspectRatio=true)
++TabletScreenResolutions=(Description="Huawei MediaPad M3",Width=768,Height=1366,AspectRatio="9:16",bCanSwapAspectRatio=true)
++TabletScreenResolutions=(Description="Microsoft Surface RT",Width=768,Height=1366,AspectRatio="9:16",bCanSwapAspectRatio=true)
++TabletScreenResolutions=(Description="Microsoft Surface Pro",Width=1080,Height=1920,AspectRatio="9:16",bCanSwapAspectRatio=true)
; common screen resolutions for television sets
-+TelevisionScreenResolutions=(Description="720p (HDTV, Blu-ray)",Width=1280,Height=720,AspectRatio="16:9")
-+TelevisionScreenResolutions=(Description="1080i, 1080p (HDTV, Blu-ray)",Width=1920,Height=1080,AspectRatio="16:9")
-+TelevisionScreenResolutions=(Description="4K Ultra HD",Width=3840,Height=2160,AspectRatio="16:9")
-+TelevisionScreenResolutions=(Description="4K Digital Cinema",Width=4096,Height=2160,AspectRatio="1.90:1")
++TelevisionScreenResolutions=(Description="720p (HDTV, Blu-ray)",Width=1280,Height=720,AspectRatio="16:9",bCanSwapAspectRatio=false)
++TelevisionScreenResolutions=(Description="1080i, 1080p (HDTV, Blu-ray)",Width=1920,Height=1080,AspectRatio="16:9",bCanSwapAspectRatio=false)
++TelevisionScreenResolutions=(Description="4K Ultra HD",Width=3840,Height=2160,AspectRatio="16:9",bCanSwapAspectRatio=false)
++TelevisionScreenResolutions=(Description="4K Digital Cinema",Width=4096,Height=2160,AspectRatio="1.90:1",bCanSwapAspectRatio=false)
[/Script/UnrealEd.LevelEditorViewportSettings]
diff --git a/Engine/Config/BaseEditorSettings.ini b/Engine/Config/BaseEditorSettings.ini
index 23168f8fd5fc..c38363cb8beb 100644
--- a/Engine/Config/BaseEditorSettings.ini
+++ b/Engine/Config/BaseEditorSettings.ini
@@ -34,6 +34,12 @@ DisplayCppFolders=True
DisplayPluginFolder=True
; The number of objects to keep in the Content Browser Recently Opened filter
NumObjectsInRecentList = 20
+; Whether to consider an asset's class name when searching by text
+IncludeClassNames=True
+; Whether to include all parts of an asset's path when searching by text
+IncludeAssetPaths=False
+; Whether to include collection names when searching by text
+IncludeCollectionNames=True
[/Script/IntroTutorials.EditorTutorialSettings]
+Categories=(Identifier="Basics",Title=NSLOCTEXT("TutorialCategories","BasicsTitle","Basics"),Description=NSLOCTEXT("TutorialCategories","BasicsDescription","Getting started with Unreal Engine 4."),Icon="PlayWorld.RepeatLastPlay",Texture=None,SortOrder=100)
diff --git a/Engine/Config/BaseEngine.ini b/Engine/Config/BaseEngine.ini
index a6c95f40bb4b..efe456d1030f 100644
--- a/Engine/Config/BaseEngine.ini
+++ b/Engine/Config/BaseEngine.ini
@@ -43,6 +43,8 @@ LargestMemoryBucket_MinGB=32
LargerMemoryBucket_MinGB=12
DefaultMemoryBucket_MinGB=8
SmallerMemoryBucket_MinGB=6
+; if SmallestMemoryBucket_MinGB is set, then the engine will throw up an error and exit(0) if the device has less
+SmallestMemoryBucket_MinGB=0
[/Script/Engine.Engine]
ConsoleClassName=/Script/Engine.Console
@@ -171,6 +173,7 @@ LightingOnlyBrightness=(R=0.3,G=0.3,B=0.3,A=1.0)
+HLODColorationColors=(R=0.5,G=0.5,B=0.5,A=1.0) ; grey
MaxPixelShaderAdditiveComplexityCount=2000
MaxES2PixelShaderAdditiveComplexityCount=600
+MaxES3PixelShaderAdditiveComplexityCount=800
bSubtitlesEnabled=True
bSubtitlesForcedOff=false
DefaultSoundName=/Engine/EngineSounds/WhiteNoise.WhiteNoise
@@ -556,6 +559,9 @@ bUseStreamingPause=false
+FunctionRedirects=(OldName="NavigationSystemV1.SimpleMoveToActor",NewName="AIBlueprintHelperLibrary.SimpleMoveToActor")
+FunctionRedirects=(OldName="NavigationSystemV1.SimpleMoveToLocation",NewName="AIBlueprintHelperLibrary.SimpleMoveToLocation")
++PropertyRedirects=(OldName="UserWidget.bCanEverTick", NewName="bHasScriptImplementedTick")
++PropertyRedirects=(OldName="UserWidget.bCanEverPaint", NewName="bHasScriptImplementedPaint")
+
+PropertyRedirects=(OldName="MovieScene.FrameResolution",NewName="TickResolution")
+PropertyRedirects=(OldName="MovieScene.PlayRate",NewName="DisplayRate")
+ClassRedirects=(OldName="/Script/MovieSceneCapture.AutomatedLevelSequenceCapture", NewName="/Script/MovieSceneTools.AutomatedLevelSequenceCapture")
@@ -564,7 +570,6 @@ bUseStreamingPause=false
+ClassRedirects=(OldName="/Script/AssetScriptingUtilities.SkeletalMeshUtilitiesLibrary", NewName="/Script/EditorScriptingUtilities.EditorSkeletalMeshLibrary")
+FunctionRedirects=(OldName="StaticMeshUtilitiesLibrary.GetLODScreenSizes",NewName="EditorStaticMeshLibrary.GetLodScreenSizes")
-
[CoreUObject.Metadata]
; Note: UnrealHeaderTool should be rerun after making changes to MetadataRedirects to catch any keys specified in class headers
+MetadataRedirects=(OldKey="K2Protected", NewKey="BlueprintProtected")
@@ -941,6 +946,13 @@ WorkerTimeToLive=20
; For build machines, wait this many seconds before exiting an unused worker (float value)
BuildWorkerTimeToLive=1200
+; These values are for build machines only currently to reduce the number of SCWs spawned to reduce memory pressure
+bUseVirtualCores = False
+CookerMemoryUsedInGB = 49
+MemoryToLeaveForTheOSInGB = 3
+MemoryUsedPerSCWProcessInGB = 0.4
+
+
[DevOptions.Debug]
ShowSelectedLightmap=False
@@ -1127,6 +1139,8 @@ MaxLocalTalkers=1
MaxRemoteTalkers=16
bUseBuildIdOverride=false
BuildIdOverride=0
+
+[OnlineSubsystemMcp.OnlinePartyMcp]
PartyPendingCreateResponseTimeout=0.0
PartyPendingJoinResponseTimeout=5.0
PartyPendingLeaveResponseTimeout=5.0
@@ -1170,11 +1184,12 @@ RedirectPort=9001
[OnlineSubsystemFacebook]
bEnabled=false
+APIVer="v2.12"
[OnlineSubsystemFacebook.OnlineIdentityFacebook]
-LoginUrl="https://www.facebook.com/v2.8/dialog/oauth"
+LoginUrl="https://www.facebook.com/`ver/dialog/oauth"
LoginRedirectUrl="https://www.facebook.com/connect/login_success.html"
-MeURL="https://graph.facebook.com/v2.8/me?access_token=`token"
+MeURL="https://graph.facebook.com/`ver/me?access_token=`token"
+LoginDomains=".facebook.com"
bUsePopup=false
ProfileFields=locale
@@ -1182,10 +1197,10 @@ ProfileFields=locale
+ProfileFields=gender
[OnlineSubsystemFacebook.OnlineSharingFacebook]
-PermissionsURL="https://graph.facebook.com/v2.8/me/permissions?access_token=`token"
+PermissionsURL="https://graph.facebook.com/`ver/me/permissions?access_token=`token"
[OnlineSubsystemFacebook.OnlineFriendsFacebook]
-FriendsUrl="https://graph.facebook.com/v2.8/me/friends?fields=`fields&access_token=`token"
+FriendsUrl="https://graph.facebook.com/`ver/me/friends?fields=`fields&access_token=`token"
FriendsFields=locale
+FriendsFields=link
+FriendsFields=gender
@@ -1659,6 +1674,7 @@ bTreatRemoteAsSeparateController=False
bAllowRemoteRotation=True
bUseRemoteAsVirtualJoystick=True
bUseAbsoluteDpadValues=False
+bAllowControllers=True
bGeneratedSYMFile=False
bDisableHTTPS=false
bUseRSync=True
@@ -1706,6 +1722,7 @@ VersionDisplayName=1.0
MinSDKVersion=9
TargetSDKVersion=9
bEnableGradle=true
+bEnableLint=false
bShowLaunchImage=true
bValidateTextureFormats=true
bMultiTargetFormat_ETC1=true
@@ -1725,6 +1742,8 @@ bEnableNewKeyboard=False
bAndroidVoiceEnabled=false
bBuildWithHiddenSymbolVisibility=false
bSaveSymbols=false
+bAllowControllers=True
+bAllowIMU=True
[/Script/AndroidPlatformEditor.AndroidSDKSettings]
SDKAPILevel=latest
@@ -1918,10 +1937,10 @@ OnScreenDebugMessagesBind=(Key=Tab,bShift=False,bCtrl=True,bAlt=False,bCmd=False
GameHUDBind=(Key=Tilde,bShift=False,bCtrl=True,bAlt=False,bCmd=False)
[/Script/Engine.SkeletalMeshLODSettings]
-+LODGroups=(ScreenSize=1.0,ReductionSettings=(NumOfTrianglesPercentage=.5))
-+LODGroups=(ScreenSize=.3,ReductionSettings=(NumOfTrianglesPercentage=.25))
-+LODGroups=(ScreenSize=.15,ReductionSettings=(NumOfTrianglesPercentage=.125))
-+LODGroups=(ScreenSize=.1,ReductionSettings=(NumOfTrianglesPercentage=.06))
++LODGroups=(ScreenSize=(Default=1.0,PerPlatform=()),ReductionSettings=(NumOfTrianglesPercentage=.5))
++LODGroups=(ScreenSize=(Default=.3,PerPlatform=()),ReductionSettings=(NumOfTrianglesPercentage=.25))
++LODGroups=(ScreenSize=(Default=.15,PerPlatform=()),ReductionSettings=(NumOfTrianglesPercentage=.125))
++LODGroups=(ScreenSize=(Default=.1,PerPlatform=()),ReductionSettings=(NumOfTrianglesPercentage=.06))
[/Script/CinematicCamera.CineCameraComponent]
+FilmbackPresets=(Name="16:9 Film",FilmbackSettings=(SensorWidth=24.892,SensorHeight=14.002))
diff --git a/Engine/Config/BaseGame.ini b/Engine/Config/BaseGame.ini
index 10b2c204a655..3e3c2e249dc0 100644
--- a/Engine/Config/BaseGame.ini
+++ b/Engine/Config/BaseGame.ini
@@ -70,6 +70,27 @@ bSharedMaterialNativeLibraries=False
bShareMaterialShaderCode=False
bSkipMovies=False
++EarlyDownloaderPakFileFiles=...\Content\Internationalization\...\*.icu
++EarlyDownloaderPakFileFiles=...\Content\Internationalization\...\*.brk
++EarlyDownloaderPakFileFiles=...\Content\Internationalization\...\*.res
++EarlyDownloaderPakFileFiles=...\Content\Internationalization\...\*.nrm
++EarlyDownloaderPakFileFiles=...\Content\Internationalization\...\*.cfu
++EarlyDownloaderPakFileFiles=...\Content\Localization\...\*.*
++EarlyDownloaderPakFileFiles=...\Content\Localization\*.*
++EarlyDownloaderPakFileFiles=...\Content\Certificates\...\*.*
++EarlyDownloaderPakFileFiles=...\Content\Certificates\*.*
+; have special cased game localization so that it's not required for early pak file
++EarlyDownloaderPakFileFiles=-...\Content\Localization\Game\...\*.*
++EarlyDownloaderPakFileFiles=-...\Content\Localization\Game\*.*
++EarlyDownloaderPakFileFiles=...\Config\...\*.ini
++EarlyDownloaderPakFileFiles=...\Config\*.ini
++EarlyDownloaderPakFileFiles=...\Engine\GlobalShaderCache*.bin
++EarlyDownloaderPakFileFiles=...\Content\ShaderArchive-Global-*.ushaderbytecode
++EarlyDownloaderPakFileFiles=...\Content\Slate\*.*
++EarlyDownloaderPakFileFiles=...\Content\Slate\...\*.*
++EarlyDownloaderPakFileFiles=...\*.upluginmanifest
++EarlyDownloaderPakFileFiles=...\*.uproject
++EarlyDownloaderPakFileFiles=...\global_sf*.metalmap
[/Script/Engine.HUD]
DebugDisplay=AI
diff --git a/Engine/Config/BaseScalability.ini b/Engine/Config/BaseScalability.ini
index b39d18039626..10a0553cf91a 100644
--- a/Engine/Config/BaseScalability.ini
+++ b/Engine/Config/BaseScalability.ini
@@ -116,6 +116,7 @@ r.Shadow.CSM.TransitionScale=0.8
r.Shadow.PreShadowResolutionFactor=0.5
r.DistanceFieldShadowing=1
r.DistanceFieldAO=1
+r.AOQuality=1
r.VolumetricFog=1
r.VolumetricFog.GridPixelSize=16
r.VolumetricFog.GridSizeZ=64
@@ -135,6 +136,7 @@ r.Shadow.CSM.TransitionScale=1.0
r.Shadow.PreShadowResolutionFactor=1.0
r.DistanceFieldShadowing=1
r.DistanceFieldAO=1
+r.AOQuality=2
r.VolumetricFog=1
r.VolumetricFog.GridPixelSize=8
r.VolumetricFog.GridSizeZ=128
@@ -154,6 +156,7 @@ r.Shadow.CSM.TransitionScale=1.0
r.Shadow.PreShadowResolutionFactor=1.0
r.DistanceFieldShadowing=1
r.DistanceFieldAO=1
+r.AOQuality=2
r.VolumetricFog=1
r.VolumetricFog.GridPixelSize=4
r.VolumetricFog.GridSizeZ=128
@@ -323,7 +326,8 @@ r.DOF.Kernel.MaxBackgroundRadius=0.025
; Must be used with r.streaming.usepertexturebias set to 1. Otherwise, all textures will have a constant 16 mip bias
r.Streaming.MipBias=16
r.Streaming.AmortizeCPUToGPUCopy=1
-r.Streaming.MaxNumTexturesToStreamPerFrame=2
+r.Streaming.MaxNumTexturesToStreamPerFrame=1
+r.Streaming.Boost=0.3
r.MaxAnisotropy=0
r.Streaming.LimitPoolSizeToVRAM=1
r.Streaming.PoolSize=1000
@@ -333,6 +337,7 @@ r.Streaming.MaxEffectiveScreenSize=0
r.Streaming.MipBias=1
r.Streaming.AmortizeCPUToGPUCopy=0
r.Streaming.MaxNumTexturesToStreamPerFrame=0
+r.Streaming.Boost=1
r.MaxAnisotropy=2
r.Streaming.LimitPoolSizeToVRAM=1
r.Streaming.PoolSize=2000
@@ -342,6 +347,7 @@ r.Streaming.MaxEffectiveScreenSize=0
r.Streaming.MipBias=0
r.Streaming.AmortizeCPUToGPUCopy=0
r.Streaming.MaxNumTexturesToStreamPerFrame=0
+r.Streaming.Boost=1
r.MaxAnisotropy=4
r.Streaming.LimitPoolSizeToVRAM=1
r.Streaming.PoolSize=3000
@@ -351,6 +357,7 @@ r.Streaming.MaxEffectiveScreenSize=0
r.Streaming.MipBias=0
r.Streaming.AmortizeCPUToGPUCopy=0
r.Streaming.MaxNumTexturesToStreamPerFrame=0
+r.Streaming.Boost=1
r.MaxAnisotropy=8
r.Streaming.LimitPoolSizeToVRAM=0
r.Streaming.PoolSize=3000
@@ -360,6 +367,7 @@ r.Streaming.MaxEffectiveScreenSize=0
r.Streaming.MipBias=0
r.Streaming.AmortizeCPUToGPUCopy=0
r.Streaming.MaxNumTexturesToStreamPerFrame=0
+r.Streaming.Boost=1
r.MaxAnisotropy=8
r.Streaming.LimitPoolSizeToVRAM=0
r.Streaming.PoolSize=3000
diff --git a/Engine/Config/ConsoleVariables.ini b/Engine/Config/ConsoleVariables.ini
index 45a844240696..73129b952a93 100644
--- a/Engine/Config/ConsoleVariables.ini
+++ b/Engine/Config/ConsoleVariables.ini
@@ -1,7 +1,7 @@
; ConsoleVariables.ini
;
; Why we have this file:
-; A developer can change it locally to save time not having to type repetitive console variable settings.
+; A developer can change it locally to save time not having to type repetitive console variable settings.
; This file should be in the source control database (for the comments and to know where to find it) but kept empty expect from comments.
;
; Details:
diff --git a/Engine/Config/IOS/BaseIOSEngine.ini b/Engine/Config/IOS/BaseIOSEngine.ini
new file mode 100644
index 000000000000..7a8cc02b236f
--- /dev/null
+++ b/Engine/Config/IOS/BaseIOSEngine.ini
@@ -0,0 +1,2 @@
+[OnlineSubsystem]
+NativePlatformService=IOS
\ No newline at end of file
diff --git a/Engine/Config/IOS/IOSEngine.ini b/Engine/Config/IOS/IOSEngine.ini
index d557e15c652b..bf0a3d04a40d 100644
--- a/Engine/Config/IOS/IOSEngine.ini
+++ b/Engine/Config/IOS/IOSEngine.ini
@@ -17,11 +17,12 @@ AudioDeviceModuleName=IOSAudio
AudioMixerModuleName=AudioMixerAudioUnit
; Defines a platform-specific volume headroom (in dB) for audio to provide better platform consistency with respect to volume levels.
-PlatformHeadroomDB=0
+PlatformHeadroomDB=-6
[PlatformMemoryBuckets]
DefaultMemoryBucket_MinGB=4
SmallerMemoryBucket_MinGB=3
+SmallestMemoryBucket_MinGB=2
[OnlineSubsystem]
DefaultPlatformService=MCP
@@ -49,7 +50,7 @@ DefaultPlatformService=IOSLocalNotification
[ConsoleVariables]
Slate.CacheRenderData=0
r.AllowOcclusionQueries=0
-r.Streaming.FramesForFullUpdate=30
+Fort.Scalability.InGameTextureStreamingFramesForFullUpdate=30
[TextureStreaming]
; PoolSizeVRAMPercentage is how much percentage of GPU Dedicated VRAM should be used as a TexturePool cache for streaming textures (0 - unlimited streaming)
diff --git a/Engine/Extras/LLDBDataFormatters/UE4DataFormatters.py b/Engine/Extras/LLDBDataFormatters/UE4DataFormatters.py
index 5fea53be3b15..389c90310c2c 100644
--- a/Engine/Extras/LLDBDataFormatters/UE4DataFormatters.py
+++ b/Engine/Extras/LLDBDataFormatters/UE4DataFormatters.py
@@ -487,10 +487,10 @@ class UE4SetSynthProvider:
HasObject = 0
if self.SecondaryDataDataVal > 0:
Expr = '(bool)((((int*)'+str(self.SecondaryDataDataVal)+')['+str(index)+'/32] >> '+str(index)+') & 1)'
- HasObject = self.AllocationFlagsSecondaryDataData.CreateValueFromExpression('['+str(index)+']', Expr).GetValueAsUnsigned(0)
+ HasObject = 1 ##self.AllocationFlagsSecondaryDataData.CreateValueFromExpression('['+str(index)+']', Expr).GetValueAsUnsigned(0)
else:
Expr = '(bool)((((int*)'+str(self.AllocationFlagsInlineDataAddr)+')['+str(index)+'/32] >> '+str(index)+') & 1)'
- HasObject = self.AllocationFlagsInlineData.CreateValueFromExpression('['+str(index)+']', Expr).GetValueAsUnsigned(0)
+ HasObject = 1 ##self.AllocationFlagsInlineData.CreateValueFromExpression('['+str(index)+']', Expr).GetValueAsUnsigned(0)
if HasObject == 1:
return self.AllocatorInstanceData.CreateChildAtOffset('['+str(index)+']',offset,self.ElementType)
@@ -577,12 +577,12 @@ class UE4MapSynthProvider:
try:
offset = index * self.ElementTypeSize
HasObject = 0
- if self.SecondaryDataDataVal > 0:
+ if self.SecondaryDataDataVal != 0:
Expr = '(bool)((((unsigned int*)'+str(self.SecondaryDataDataVal)+')['+str(index)+'/32] >> '+str(index)+') & 1)'
- HasObject = self.AllocationFlagsSecondaryDataData.CreateValueFromExpression('['+str(index)+']', Expr).GetValueAsUnsigned(0)
+ HasObject = 1 ##self.AllocationFlagsSecondaryDataData.CreateValueFromExpression('['+str(index)+']', Expr).GetValueAsUnsigned(0)
else:
Expr = '(bool)((((unsigned int*)'+str(self.AllocationFlagsInlineDataAddr)+')['+str(index)+'/32] >> '+str(index)+') & 1)'
- HasObject = self.AllocationFlagsInlineData.CreateValueFromExpression('['+str(index)+']', Expr).GetValueAsUnsigned(0)
+ HasObject = 1 ##self.AllocationFlagsInlineData.CreateValueFromExpression('['+str(index)+']', Expr).GetValueAsUnsigned(0)
if HasObject == 1:
return self.AllocatorInstanceData.CreateChildAtOffset('['+str(index)+']',offset,self.ElementType)
diff --git a/Engine/Extras/Xcode/xcodecheckout.sh b/Engine/Extras/Xcode/xcodecheckout.sh
new file mode 100755
index 000000000000..7622eb4069e1
--- /dev/null
+++ b/Engine/Extras/Xcode/xcodecheckout.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+
+# This script can be specified in Xcode's behaviors to checkout files that are locked for editing.
+# It assumes the P4 commandline tools are installed, and the active p4config points to a workspace
+# that maps to the path of the file
+
+ /usr/local/bin/p4 edit ${XcodeAlertAffectedPaths}
+
diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperTerrainMaterial.h b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperTerrainMaterial.h
index 2aa1254bd0df..13f406ab65a9 100644
--- a/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperTerrainMaterial.h
+++ b/Engine/Plugins/2D/Paper2D/Source/Paper2D/Classes/PaperTerrainMaterial.h
@@ -60,6 +60,7 @@ struct FPaperTerrainMaterialRule
, MaximumAngle(360.0f)
, bEnableCollision(true)
, CollisionOffset(0.0f)
+ , DrawOrder(0)
{
}
};
diff --git a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/PaperSpriteThumbnailRenderer.cpp b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/PaperSpriteThumbnailRenderer.cpp
index 54456e95dc7a..e3cd005c15df 100644
--- a/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/PaperSpriteThumbnailRenderer.cpp
+++ b/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/PaperSpriteThumbnailRenderer.cpp
@@ -27,7 +27,7 @@ void UPaperSpriteThumbnailRenderer::DrawGrid(int32 X, int32 Y, uint32 Width, uin
static UTexture2D* GridTexture = nullptr;
if (GridTexture == nullptr)
{
- GridTexture = LoadObject(nullptr, TEXT("/Engine/EngineMaterials/DefaultWhiteGrid.DefaultWhiteGrid"), nullptr, LOAD_None, nullptr);
+ GridTexture = LoadObject(nullptr, TEXT("/Engine/EngineMaterials/DefaultDiffuse_TC_Masks.DefaultDiffuse_TC_Masks"), nullptr, LOAD_None, nullptr);
}
const bool bAlphaBlend = false;
diff --git a/Engine/Plugins/Animation/LiveLink/Source/LiveLink/Private/AnimNode_LiveLinkPose.cpp b/Engine/Plugins/Animation/LiveLink/Source/LiveLink/Private/AnimNode_LiveLinkPose.cpp
index ffd49ee3a3b2..b355ee00ad85 100644
--- a/Engine/Plugins/Animation/LiveLink/Source/LiveLink/Private/AnimNode_LiveLinkPose.cpp
+++ b/Engine/Plugins/Animation/LiveLink/Source/LiveLink/Private/AnimNode_LiveLinkPose.cpp
@@ -11,6 +11,7 @@
FAnimNode_LiveLinkPose::FAnimNode_LiveLinkPose()
: RetargetAsset(ULiveLinkRemapAsset::StaticClass())
+ , CurrentRetargetAsset(nullptr)
, LiveLinkClient(nullptr)
{
}
diff --git a/Engine/Plugins/Animation/LiveLink/Source/LiveLink/Private/LiveLinkRetargetAssetReference.cpp b/Engine/Plugins/Animation/LiveLink/Source/LiveLink/Private/LiveLinkRetargetAssetReference.cpp
index 874fb5bbc0a4..2b6dc7995ba6 100644
--- a/Engine/Plugins/Animation/LiveLink/Source/LiveLink/Private/LiveLinkRetargetAssetReference.cpp
+++ b/Engine/Plugins/Animation/LiveLink/Source/LiveLink/Private/LiveLinkRetargetAssetReference.cpp
@@ -3,7 +3,8 @@
#include "LiveLinkRetargetAssetReference.h"
#include "LiveLinkRemapAsset.h"
-FLiveLinkRetargetAssetReference::FLiveLinkRetargetAssetReference() //: CurrentRetargetAsset(ULiveLinkRemapAsset::StaticClass())
+FLiveLinkRetargetAssetReference::FLiveLinkRetargetAssetReference()
+ : CurrentRetargetAsset(nullptr)
{
}
diff --git a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h
index 6324985f523f..f50feb898db5 100644
--- a/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h
+++ b/Engine/Plugins/Developer/GitSourceControl/Source/GitSourceControl/Private/GitSourceControlProvider.h
@@ -54,6 +54,7 @@ public:
virtual bool IsEnabled() const override;
virtual bool IsAvailable() const override;
virtual const FName& GetName(void) const override;
+ virtual bool QueryStateBranchConfig(const FString& ConfigSrc, const FString& ConfigDest) override { return false; }
virtual void RegisterStateBranches(const TArray& BranchNames, const FString& ContentRoot) override {}
virtual int32 GetStateBranchIndex(const FString& InBranchName) const override { return INDEX_NONE; }
virtual ECommandResult::Type GetState( const TArray& InFiles, TArray< TSharedRef >& OutState, EStateCacheUsage::Type InStateCacheUsage ) override;
diff --git a/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceOperations.cpp b/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceOperations.cpp
index fa9525a70e5d..3aed975b5c5a 100644
--- a/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceOperations.cpp
+++ b/Engine/Plugins/Developer/OneSkyLocalizationService/Source/OneSkyLocalizationService/Private/OneSkyLocalizationServiceOperations.cpp
@@ -83,7 +83,7 @@ static bool DeserializeResponseToStruct(void* OutStruct, UStruct& TypeInfo, FHtt
// Write string to FMemoryWriter to force unicode
TArray InBytes;
FMemoryWriter Writer(InBytes);
- Writer.ArForceUnicode = true;
+ Writer.SetForceUnicode(true);
Writer << ResponseStr;
FMemoryReader Reader(InBytes);
@@ -281,7 +281,7 @@ bool FOneSkyCreateProjectGroupWorker::Execute(class FOneSkyLocalizationServiceCo
// Write string to FMemoryWriter to force unicode
//TArray InBytes;
//FMemoryWriter Writer(InBytes);
- //Writer.ArForceUnicode = true;
+ //Writer.SetForceUnicode(true);
//Writer << Parameters;
//FMemoryReader Reader(InBytes);
//// FMemoryWriter writes size of string at beginning, need to ignore this or parsing errors occur
diff --git a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceConnection.cpp b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceConnection.cpp
index 4f476eba196e..798c698c5ef8 100644
--- a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceConnection.cpp
+++ b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceConnection.cpp
@@ -532,7 +532,7 @@ bool FPerforceConnection::GetWorkspaceList(const FPerforceConnectionInfo& InConn
}
else
{
- UE_LOG(LogSourceControl, Error, TEXT(" %s client specs rejected due to root directory mismatch (%s)"), *ClientName, *ClientRootPath);
+ UE_LOG(LogSourceControl, Display, TEXT(" %s client specs rejected due to root directory mismatch (%s)"), *ClientName, *ClientRootPath);
}
//Other useful fields: Description, Owner, Host
@@ -540,7 +540,7 @@ bool FPerforceConnection::GetWorkspaceList(const FPerforceConnectionInfo& InConn
}
else
{
- UE_LOG(LogSourceControl, Error, TEXT(" %s client specs rejected due to host name mismatch (%s)"), *ClientName, *HostName);
+ UE_LOG(LogSourceControl, Display, TEXT(" %s client specs rejected due to host name mismatch (%s)"), *ClientName, *HostName);
}
}
}
diff --git a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlOperations.cpp b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlOperations.cpp
index 082c6e751a57..7edc5c4d16f8 100644
--- a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlOperations.cpp
+++ b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlOperations.cpp
@@ -1148,6 +1148,13 @@ bool FPerforceUpdateStatusWorker::Execute(FPerforceSourceControlCommand& InComma
FString BranchFile;
if (File.Split(ContentRoot, nullptr, &BranchFile))
{
+ // Ignore collection files when querying status branches
+ FString Ext = FPaths::GetExtension(BranchFile, true);
+ if (Ext.Compare(TEXT(".collection"), ESearchCase::IgnoreCase) == 0)
+ {
+ continue;
+ }
+
TArray Args = { Branch, ContentRoot, BranchFile };
Parameters.Add(FString::Format(TEXT("{0}/{1}{2}"), Args));
}
diff --git a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.cpp b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.cpp
index 8dd60e3571c9..f0ddf90c7f6f 100644
--- a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.cpp
+++ b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.cpp
@@ -558,6 +558,60 @@ ECommandResult::Type FPerforceSourceControlProvider::IssueCommand(FPerforceSourc
}
}
+bool FPerforceSourceControlProvider::QueryStateBranchConfig(const FString& ConfigSrc, const FString& ConfigDest)
+{
+
+ if (ConfigSrc.Len() == 0 || ConfigDest.Len() == 0)
+ {
+ return false;
+ }
+
+ // Request branch configuration from depot
+ FPerforceSourceControlModule& PerforceSourceControl = FModuleManager::LoadModuleChecked("PerforceSourceControl");
+ FScopedPerforceConnection ScopedConnection(EConcurrency::Synchronous, PerforceSourceControl.AccessSettings().GetConnectionInfo());
+ if (ScopedConnection.IsValid())
+ {
+ FPerforceConnection& Connection = ScopedConnection.GetConnection();
+ FP4RecordSet Records;
+ TArray Parameters;
+ TArray ErrorMessages;
+ Parameters.Add(TEXT("-o"));
+ Parameters.Add(*ConfigDest);
+ Parameters.Add(*ConfigSrc);
+
+ FText GeneralErrorMessage = LOCTEXT("StatusBranchConfigGeneralFailure", "Unable to retrieve status branch configuration from depot");
+
+ bool bConnectionDropped = false;
+ if (Connection.RunCommand(TEXT("print"), Parameters, Records, ErrorMessages, FOnIsCancelled(), bConnectionDropped))
+ {
+ if (Records.Num() < 1 || Records[0][TEXT("depotFile")] != ConfigSrc)
+ {
+ FMessageLog("SourceControl").Error(GeneralErrorMessage);
+ return false;
+ }
+ }
+ else
+ {
+ FMessageLog("SourceControl").Error(GeneralErrorMessage);
+
+ // output specific errors if any
+ for (int32 ErrorIndex = 0; ErrorIndex < ErrorMessages.Num(); ++ErrorIndex)
+ {
+ FMessageLog("SourceControl").Error(ErrorMessages[ErrorIndex]);
+ }
+
+ return false;
+ }
+ }
+ else
+ {
+ FMessageLog("SourceControl").Error(LOCTEXT("StatusBranchConfigNoConnection", "Unable to retrieve status branch configuration from depot, no connection"));
+ return false;
+ }
+
+ return true;
+}
+
void FPerforceSourceControlProvider::RegisterStateBranches(const TArray& BranchNames, const FString& ContentRootIn)
{
StatusBranchNames = BranchNames;
diff --git a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.h b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.h
index b70e134da246..0e01873b22a7 100644
--- a/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.h
+++ b/Engine/Plugins/Developer/PerforceSourceControl/Source/PerforceSourceControl/Private/PerforceSourceControlProvider.h
@@ -30,6 +30,7 @@ public:
virtual bool IsEnabled() const override;
virtual bool IsAvailable() const override;
virtual const FName& GetName(void) const override;
+ virtual bool QueryStateBranchConfig(const FString& ConfigSrc, const FString& ConfigDest) override;
virtual void RegisterStateBranches(const TArray& BranchNames, const FString& ContentRootIn) override;
virtual int32 GetStateBranchIndex(const FString& BranchName) const override;
virtual ECommandResult::Type GetState( const TArray& InFiles, TArray< TSharedRef >& OutState, EStateCacheUsage::Type InStateCacheUsage ) override;
diff --git a/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.h b/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.h
index 8e587ec9b128..844f2fd7dff6 100644
--- a/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.h
+++ b/Engine/Plugins/Developer/SubversionSourceControl/Source/SubversionSourceControl/Private/SubversionSourceControlProvider.h
@@ -29,6 +29,7 @@ public:
virtual bool IsEnabled() const override;
virtual bool IsAvailable() const override;
virtual const FName& GetName(void) const override;
+ virtual bool QueryStateBranchConfig(const FString& ConfigSrc, const FString& ConfigDest) override { return false; }
virtual void RegisterStateBranches(const TArray& BranchNames, const FString& ContentRoot) override {}
virtual int32 GetStateBranchIndex(const FString& BranchName) const override { return INDEX_NONE; }
virtual ECommandResult::Type GetState( const TArray& InFiles, TArray< TSharedRef >& OutState, EStateCacheUsage::Type InStateCacheUsage ) override;
diff --git a/Engine/Plugins/Developer/VisualStudioSourceCodeAccess/Source/VisualStudioSourceCodeAccess/Private/VisualStudioSourceCodeAccessor.cpp b/Engine/Plugins/Developer/VisualStudioSourceCodeAccess/Source/VisualStudioSourceCodeAccess/Private/VisualStudioSourceCodeAccessor.cpp
index 67e4aa51af7f..37853bea3155 100644
--- a/Engine/Plugins/Developer/VisualStudioSourceCodeAccess/Source/VisualStudioSourceCodeAccess/Private/VisualStudioSourceCodeAccessor.cpp
+++ b/Engine/Plugins/Developer/VisualStudioSourceCodeAccess/Source/VisualStudioSourceCodeAccess/Private/VisualStudioSourceCodeAccessor.cpp
@@ -127,7 +127,7 @@ int32 GetVisualStudioVersionForSolution(const FString& InSolutionFile)
}
int32 Version = 0;
- Lex::FromString(Version, *VersionString);
+ LexFromString(Version, *VersionString);
return Version;
}
}
diff --git a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/AssetManagerEditorModule.cpp b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/AssetManagerEditorModule.cpp
index c9dc333e1756..708c47bdefae 100644
--- a/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/AssetManagerEditorModule.cpp
+++ b/Engine/Plugins/Editor/AssetManagerEditor/Source/AssetManagerEditor/Private/AssetManagerEditorModule.cpp
@@ -954,7 +954,7 @@ bool FAssetManagerEditorModule::GetStringValueForCustomColumn(const FAssetData&
int64 IntegerValue = 0;
if (GetIntegerValueForCustomColumn(AssetData, ColumnName, IntegerValue))
{
- OutValue = Lex::ToString(IntegerValue);
+ OutValue = LexToString(IntegerValue);
return true;
}
}
@@ -1007,7 +1007,7 @@ bool FAssetManagerEditorModule::GetStringValueForCustomColumn(const FAssetData&
{
OutValue += TEXT("+");
}
- OutValue += Lex::ToString(Chunk);
+ OutValue += LexToString(Chunk);
}
return true;
}
diff --git a/Engine/Plugins/Editor/DataValidation/Source/DataValidation/Private/DataValidationModule.cpp b/Engine/Plugins/Editor/DataValidation/Source/DataValidation/Private/DataValidationModule.cpp
index bf521bc07743..4a04114fdcba 100644
--- a/Engine/Plugins/Editor/DataValidation/Source/DataValidation/Private/DataValidationModule.cpp
+++ b/Engine/Plugins/Editor/DataValidation/Source/DataValidation/Private/DataValidationModule.cpp
@@ -90,10 +90,13 @@ void FDataValidationModule::ShutdownModule()
{
if (!IsRunningCommandlet() && !IsRunningGame())
{
- FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked(TEXT("ContentBrowser"));
- TArray& CBMenuExtenderDelegates = ContentBrowserModule.GetAllAssetViewContextMenuExtenders();
- CBMenuExtenderDelegates.RemoveAll([this](const FContentBrowserMenuExtender_SelectedAssets& Delegate) { return Delegate.GetHandle() == ContentBrowserAssetExtenderDelegateHandle; });
- CBMenuExtenderDelegates.RemoveAll([this](const FContentBrowserMenuExtender_SelectedAssets& Delegate) { return Delegate.GetHandle() == ContentBrowserPathExtenderDelegateHandle; });
+ FContentBrowserModule* ContentBrowserModule = (FContentBrowserModule*)(FModuleManager::Get().GetModule(TEXT("ContentBrowser")));
+ if (ContentBrowserModule)
+ {
+ TArray& CBMenuExtenderDelegates = ContentBrowserModule->GetAllAssetViewContextMenuExtenders();
+ CBMenuExtenderDelegates.RemoveAll([this](const FContentBrowserMenuExtender_SelectedAssets& Delegate) { return Delegate.GetHandle() == ContentBrowserAssetExtenderDelegateHandle; });
+ CBMenuExtenderDelegates.RemoveAll([this](const FContentBrowserMenuExtender_SelectedAssets& Delegate) { return Delegate.GetHandle() == ContentBrowserPathExtenderDelegateHandle; });
+ }
// remove menu extension
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked("LevelEditor");
diff --git a/Engine/Plugins/Editor/GLTFImporter/Source/GLTFImporter/Private/GLTFImportFactory.cpp b/Engine/Plugins/Editor/GLTFImporter/Source/GLTFImporter/Private/GLTFImportFactory.cpp
index 77fb423f5d34..232c02e1df6e 100644
--- a/Engine/Plugins/Editor/GLTFImporter/Source/GLTFImporter/Private/GLTFImportFactory.cpp
+++ b/Engine/Plugins/Editor/GLTFImporter/Source/GLTFImporter/Private/GLTFImportFactory.cpp
@@ -11,9 +11,9 @@
#include "Engine/StaticMesh.h"
#include "RawMesh.h"
#include "Serialization/ArrayReader.h"
+#include "Editor/UnrealEd/Public/Editor.h"
#include "Serialization/JsonReader.h"
#include "Serialization/JsonSerializer.h"
-#include "Editor/UnrealEd/Public/Editor.h"
#define LOCTEXT_NAMESPACE "GLTFFactory"
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsEditorModule.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsEditorModule.cpp
index 446a2e1b223d..2321d9296dae 100644
--- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsEditorModule.cpp
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsEditorModule.cpp
@@ -51,7 +51,7 @@ public:
PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTag", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagCustomizationPublic::MakeInstance));
PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTagQuery", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagQueryCustomization::MakeInstance));
- PropertyModule.RegisterCustomClassLayout(UGameplayTagsList::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FGameplayTagsSettingsCustomization::MakeInstance));
+ PropertyModule.RegisterCustomClassLayout(UGameplayTagsSettings::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FGameplayTagsSettingsCustomization::MakeInstance));
PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTagReferenceHelper", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagReferenceHelperDetails::MakeInstance));
PropertyModule.RegisterCustomPropertyTypeLayout("GameplayTagCreationWidgetHelper", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FGameplayTagCreationWidgetHelperDetails::MakeInstance));
@@ -74,12 +74,6 @@ public:
LOCTEXT("GameplayTagSettingsNameDesc", "GameplayTag Settings"),
GetMutableDefault()
);
-
- SettingsModule->RegisterSettings("Project", "Project", "GameplayTags Developer",
- LOCTEXT("GameplayTagDeveloperSettingsName", "GameplayTags Developer"),
- LOCTEXT("GameplayTagDeveloperSettingsNameDesc", "GameplayTag Developer Settings"),
- GetMutableDefault()
- );
}
GameplayTagPackageName = FGameplayTag::StaticStruct()->GetOutermost()->GetFName();
@@ -236,6 +230,7 @@ public:
TArray Sources;
Manager.FindTagSourcesWithType(EGameplayTagSourceType::TagList, Sources);
+ Manager.FindTagSourcesWithType(EGameplayTagSourceType::RestrictedTagList, Sources);
for (const FGameplayTagSource* Source : Sources)
{
@@ -313,7 +308,7 @@ public:
return false;
}
- virtual bool AddNewGameplayTagToINI(const FString& NewTag, const FString& Comment, FName TagSourceName) override
+ virtual bool AddNewGameplayTagToINI(const FString& NewTag, const FString& Comment, FName TagSourceName, bool bIsRestrictedTag, bool bAllowNonRestrictedChildren) override
{
UGameplayTagsManager& Manager = UGameplayTagsManager::Get();
@@ -341,6 +336,67 @@ public:
return false;
}
+ if (bIsRestrictedTag)
+ {
+ // restricted tags can't be children of non-restricted tags
+ FString AncestorTag = NewTag;
+ bool bWasSplit = NewTag.Split(TEXT("."), &AncestorTag, nullptr, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
+ while (bWasSplit)
+ {
+ if (Manager.IsDictionaryTag(FName(*AncestorTag)))
+ {
+ FString TagComment;
+ FName Source;
+ bool bIsExplicit;
+ bool bIsRestricted;
+ bool bAllowsNonRestrictedChildren;
+
+ Manager.GetTagEditorData(*AncestorTag, TagComment, Source, bIsExplicit, bIsRestricted, bAllowsNonRestrictedChildren);
+ if (bIsRestricted)
+ {
+ break;
+ }
+ ShowNotification(FText::Format(LOCTEXT("AddRestrictedTagFailure", "Failed to add restricted gameplay tag {0}, {1} is not a restricted tag"), FText::FromString(NewTag), FText::FromString(AncestorTag)), 10.0f);
+
+ return false;
+ }
+
+ bWasSplit = AncestorTag.Split(TEXT("."), &AncestorTag, nullptr, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
+ }
+ }
+ else
+ {
+ // non-restricted tags can only be children of restricted tags if the restricted tag allows it
+ FString AncestorTag = NewTag;
+ bool bWasSplit = NewTag.Split(TEXT("."), &AncestorTag, nullptr, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
+ while (bWasSplit)
+ {
+ if (Manager.IsDictionaryTag(FName(*AncestorTag)))
+ {
+ FString TagComment;
+ FName Source;
+ bool bIsExplicit;
+ bool bIsRestricted;
+ bool bAllowsNonRestrictedChildren;
+
+ Manager.GetTagEditorData(*AncestorTag, TagComment, Source, bIsExplicit, bIsRestricted, bAllowsNonRestrictedChildren);
+ if (bIsRestricted)
+ {
+ if (bAllowsNonRestrictedChildren)
+ {
+ break;
+ }
+
+ ShowNotification(FText::Format(LOCTEXT("AddTagFailure", "Failed to add gameplay tag {0}, {1} is a restricted tag and does not allow non-restricted children"), FText::FromString(NewTag), FText::FromString(AncestorTag)), 10.0f);
+
+ return false;
+ }
+ }
+
+ bWasSplit = AncestorTag.Split(TEXT("."), &AncestorTag, nullptr, ESearchCase::IgnoreCase, ESearchDir::FromEnd);
+ }
+ }
+
if ((TagSourceName == NAME_None || TagSourceName == FGameplayTagSource::GetDefaultName()) && DevSettings && !DevSettings->DeveloperConfigName.IsEmpty())
{
// Try to use developer config file
@@ -361,23 +417,41 @@ public:
TagSource = Manager.FindOrAddTagSource(TagSourceName, EGameplayTagSourceType::TagList);
}
- if (TagSource && TagSource->SourceTagList)
+ bool bSuccess = false;
+ if (TagSource)
{
- UGameplayTagsList* TagList = TagSource->SourceTagList;
+ UObject* TagListObj = nullptr;
+ FString ConfigFileName;
- TagList->GameplayTagList.AddUnique(FGameplayTagTableRow(FName(*NewTag), Comment));
+ if (bIsRestrictedTag && TagSource->SourceRestrictedTagList)
+ {
+ URestrictedGameplayTagsList* RestrictedTagList = TagSource->SourceRestrictedTagList;
+ TagListObj = RestrictedTagList;
+ RestrictedTagList->RestrictedGameplayTagList.AddUnique(FRestrictedGameplayTagTableRow(FName(*NewTag), Comment, bAllowNonRestrictedChildren));
+ RestrictedTagList->SortTags();
+ ConfigFileName = RestrictedTagList->ConfigFileName;
+ bSuccess = true;
+ }
+ else if (TagSource->SourceTagList)
+ {
+ UGameplayTagsList* TagList = TagSource->SourceTagList;
+ TagListObj = TagList;
+ TagList->GameplayTagList.AddUnique(FGameplayTagTableRow(FName(*NewTag), Comment));
+ TagList->SortTags();
+ ConfigFileName = TagList->ConfigFileName;
+ bSuccess = true;
+ }
- TagList->SortTags();
-
- GameplayTagsUpdateSourceControl(TagList->ConfigFileName);
+ GameplayTagsUpdateSourceControl(ConfigFileName);
// Check source control before and after writing, to make sure it gets created or checked out
- TagList->UpdateDefaultConfigFile(TagList->ConfigFileName);
- GameplayTagsUpdateSourceControl(TagList->ConfigFileName);
- GConfig->LoadFile(TagList->ConfigFileName);
+ TagListObj->UpdateDefaultConfigFile(ConfigFileName);
+ GameplayTagsUpdateSourceControl(ConfigFileName);
+ GConfig->LoadFile(ConfigFileName);
}
- else
+
+ if (!bSuccess)
{
ShowNotification(FText::Format(LOCTEXT("AddTagFailure", "Failed to add gameplay tag {0} to dictionary {1}!"), FText::FromString(NewTag), FText::FromName(TagSourceName)), 10.0f);
@@ -403,13 +477,16 @@ public:
FString Comment;
FName TagSourceName;
+ bool bTagIsExplicit;
+ bool bTagIsRestricted;
+ bool bTagAllowsNonRestrictedChildren;
if (DeleteTagRedirector(TagToDelete))
{
return true;
}
-
- if (!Manager.GetTagEditorData(TagName, Comment, TagSourceName))
+
+ if (!Manager.GetTagEditorData(TagName, Comment, TagSourceName, bTagIsExplicit, bTagIsRestricted, bTagAllowsNonRestrictedChildren))
{
ShowNotification(FText::Format(LOCTEXT("RemoveTagFailureNoTag", "Cannot delete tag {0}, does not exist!"), FText::FromString(TagToDelete)), 10.0f);
@@ -521,17 +598,20 @@ public:
FString OldComment, NewComment;
FName OldTagSourceName, NewTagSourceName;
+ bool bTagIsExplicit;
+ bool bTagIsRestricted;
+ bool bTagAllowsNonRestrictedChildren;
// Delete existing redirector
DeleteTagRedirector(TagToRenameTo);
DeleteTagRedirector(TagToRename);
- if (Manager.GetTagEditorData(OldTagName, OldComment, OldTagSourceName))
+ if (Manager.GetTagEditorData(OldTagName, OldComment, OldTagSourceName, bTagIsExplicit, bTagIsRestricted, bTagAllowsNonRestrictedChildren))
{
// Add new tag if needed
- if (!Manager.GetTagEditorData(NewTagName, NewComment, NewTagSourceName))
+ if (!Manager.GetTagEditorData(NewTagName, NewComment, NewTagSourceName, bTagIsExplicit, bTagIsRestricted, bTagAllowsNonRestrictedChildren))
{
- if (!AddNewGameplayTagToINI(TagToRenameTo, OldComment, OldTagSourceName))
+ if (!AddNewGameplayTagToINI(TagToRenameTo, OldComment, OldTagSourceName, bTagIsRestricted, bTagAllowsNonRestrictedChildren))
{
// Failed to add new tag, so fail
return false;
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsSettingsCustomization.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsSettingsCustomization.cpp
index 4ee40c216903..79ce4b719ea1 100644
--- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsSettingsCustomization.cpp
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsSettingsCustomization.cpp
@@ -33,9 +33,9 @@ void FGameplayTagsSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder&
IDetailCategoryBuilder& GameplayTagsCategory = DetailLayout.EditCategory("GameplayTags");
{
TArray> GameplayTagsProperties;
- GameplayTagsCategory.GetDefaultProperties(GameplayTagsProperties, true, false);
+ GameplayTagsCategory.GetDefaultProperties(GameplayTagsProperties, true, true);
- TSharedPtr TagListProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UGameplayTagsList, GameplayTagList));
+ TSharedPtr TagListProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UGameplayTagsList, GameplayTagList), UGameplayTagsList::StaticClass());
TagListProperty->MarkHiddenByCustomization();
for (TSharedPtr Property : GameplayTagsProperties)
@@ -62,10 +62,49 @@ void FGameplayTagsSettingsCustomization::CustomizeDetails(IDetailLayoutBuilder&
.GameplayTagUIMode(EGameplayTagUIMode::ManagementMode)
.MaxHeight(MaxPropertyHeight)
.OnTagChanged(this, &FGameplayTagsSettingsCustomization::OnTagChanged)
+ .RestrictedTags(false)
];
}
}
}
+
+ IDetailCategoryBuilder& AdvancedGameplayTagsCategory = DetailLayout.EditCategory("Advanced Gameplay Tags");
+ {
+ TArray> GameplayTagsProperties;
+ AdvancedGameplayTagsCategory.GetDefaultProperties(GameplayTagsProperties, true, true);
+
+ TSharedPtr RestrictedTagListProperty = DetailLayout.GetProperty(GET_MEMBER_NAME_CHECKED(UGameplayTagsSettings, RestrictedTagList));
+ RestrictedTagListProperty->MarkHiddenByCustomization();
+
+ for (TSharedPtr Property : GameplayTagsProperties)
+ {
+ if (Property->GetProperty() == RestrictedTagListProperty->GetProperty())
+ {
+ // Create a custom widget for the restricted tag list
+
+ AdvancedGameplayTagsCategory.AddCustomRow(RestrictedTagListProperty->GetPropertyDisplayName(), true)
+ .NameContent()
+ [
+ RestrictedTagListProperty->CreatePropertyNameWidget()
+ ]
+ .ValueContent()
+ .MaxDesiredWidth(MaxPropertyWidth)
+ [
+ SAssignNew(RestrictedTagWidget, SGameplayTagWidget, TArray())
+ .Filter(TEXT(""))
+ .MultiSelect(false)
+ .GameplayTagUIMode(EGameplayTagUIMode::ManagementMode)
+ .MaxHeight(MaxPropertyHeight)
+ .OnTagChanged(this, &FGameplayTagsSettingsCustomization::OnTagChanged)
+ .RestrictedTags(true)
+ ];
+ }
+ else
+ {
+ AdvancedGameplayTagsCategory.AddProperty(Property);
+ }
+ }
+ }
}
void FGameplayTagsSettingsCustomization::OnTagChanged()
@@ -74,6 +113,11 @@ void FGameplayTagsSettingsCustomization::OnTagChanged()
{
TagWidget->RefreshTags();
}
+
+ if (RestrictedTagWidget.IsValid())
+ {
+ RestrictedTagWidget->RefreshTags();
+ }
}
void FGameplayTagsSettingsCustomization::OnTagTreeChanged()
@@ -82,6 +126,11 @@ void FGameplayTagsSettingsCustomization::OnTagTreeChanged()
{
TagWidget->RefreshOnNextTick();
}
+
+ if (RestrictedTagWidget.IsValid())
+ {
+ RestrictedTagWidget->RefreshOnNextTick();
+ }
}
#undef LOCTEXT_NAMESPACE
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsSettingsCustomization.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsSettingsCustomization.h
index 6a86e2a95619..cda259df7306 100644
--- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsSettingsCustomization.h
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/GameplayTagsSettingsCustomization.h
@@ -33,4 +33,6 @@ private:
void OnTagTreeChanged();
TSharedPtr TagWidget;
+
+ TSharedPtr RestrictedTagWidget;
};
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagSourceWidget.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagSourceWidget.cpp
new file mode 100644
index 000000000000..9242bcac1500
--- /dev/null
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagSourceWidget.cpp
@@ -0,0 +1,108 @@
+// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
+
+#include "SAddNewGameplayTagSourceWidget.h"
+#include "DetailLayoutBuilder.h"
+#include "GameplayTagsSettings.h"
+#include "GameplayTagsEditorModule.h"
+#include "GameplayTagsModule.h"
+#include "Widgets/Input/SButton.h"
+
+#define LOCTEXT_NAMESPACE "AddNewGameplayTagSourceWidget"
+
+void SAddNewGameplayTagSourceWidget::Construct(const FArguments& InArgs)
+{
+ FText HintText = LOCTEXT("NewSourceNameHint", "SourceName.ini");
+ DefaultNewName = InArgs._NewSourceName;
+ if (DefaultNewName.IsEmpty() == false)
+ {
+ HintText = FText::FromString(DefaultNewName);
+ }
+
+ bShouldGetKeyboardFocus = false;
+
+ OnGameplayTagSourceAdded = InArgs._OnGameplayTagSourceAdded;
+
+ ChildSlot
+ [
+ SNew(SVerticalBox)
+
+ // Tag Name
+ + SVerticalBox::Slot()
+ .AutoHeight()
+ .VAlign(VAlign_Top)
+ [
+ SNew(SHorizontalBox)
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 4.0f)
+ .AutoWidth()
+ [
+ SNew(STextBlock)
+ .Text(LOCTEXT("NewSourceName", "Name:"))
+ ]
+
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 2.0f)
+ .FillWidth(1.0f)
+ .HAlign(HAlign_Right)
+ [
+ SAssignNew(SourceNameTextBox, SEditableTextBox)
+ .MinDesiredWidth(240.0f)
+ .HintText(HintText)
+ ]
+ ]
+
+ // Add Source Button
+ +SVerticalBox::Slot()
+ .AutoHeight()
+ .VAlign(VAlign_Top)
+ .HAlign(HAlign_Center)
+ .Padding(8.0f)
+ [
+ SNew(SHorizontalBox)
+ + SHorizontalBox::Slot()
+ .AutoWidth()
+ [
+ SNew(SButton)
+ .Text(LOCTEXT("AddNew", "Add New Source"))
+ .OnClicked(this, &SAddNewGameplayTagSourceWidget::OnAddNewSourceButtonPressed)
+ ]
+ ]
+ ];
+
+ Reset();
+}
+
+void SAddNewGameplayTagSourceWidget::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
+{
+ if (bShouldGetKeyboardFocus)
+ {
+ bShouldGetKeyboardFocus = false;
+ FSlateApplication::Get().SetKeyboardFocus(SourceNameTextBox.ToSharedRef(), EFocusCause::SetDirectly);
+ }
+}
+
+void SAddNewGameplayTagSourceWidget::Reset()
+{
+ SetSourceName();
+}
+
+void SAddNewGameplayTagSourceWidget::SetSourceName(const FText& InName)
+{
+ SourceNameTextBox->SetText(InName.IsEmpty() ? FText::FromString(DefaultNewName) : InName);
+}
+
+FReply SAddNewGameplayTagSourceWidget::OnAddNewSourceButtonPressed()
+{
+ UGameplayTagsManager& Manager = UGameplayTagsManager::Get();
+
+ if (!SourceNameTextBox->GetText().EqualTo(FText::FromString(DefaultNewName)))
+ {
+ Manager.FindOrAddTagSource(*SourceNameTextBox->GetText().ToString(), EGameplayTagSourceType::TagList);
+ }
+
+ IGameplayTagsModule::OnTagSettingsChanged.Broadcast();
+
+ return FReply::Handled();
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagSourceWidget.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagSourceWidget.h
new file mode 100644
index 000000000000..1291f7a748c7
--- /dev/null
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagSourceWidget.h
@@ -0,0 +1,55 @@
+// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GameplayTagsManager.h"
+#include "Input/Reply.h"
+#include "Widgets/SWidget.h"
+#include "Widgets/SCompoundWidget.h"
+#include "Widgets/DeclarativeSyntaxSupport.h"
+#include "Widgets/Input/SEditableTextBox.h"
+#include "Widgets/Input/SComboBox.h"
+
+/** Widget allowing the user to create new gameplay tags */
+class SAddNewGameplayTagSourceWidget : public SCompoundWidget
+{
+public:
+
+ DECLARE_DELEGATE_OneParam( FOnGameplayTagSourceAdded, const FString& /*SourceName*/);
+
+ SLATE_BEGIN_ARGS(SAddNewGameplayTagSourceWidget)
+ : _NewSourceName(TEXT(""))
+ {}
+ SLATE_EVENT(FOnGameplayTagSourceAdded, OnGameplayTagSourceAdded ) // Callback for when a new source is added
+ SLATE_ARGUMENT( FString, NewSourceName ) // String that will initially populate the New Source Name field
+ SLATE_END_ARGS();
+
+ virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override;
+
+ void Construct( const FArguments& InArgs);
+
+ /** Resets all input fields */
+ void Reset();
+
+private:
+
+ /** Sets the name of the source. Uses the default if the name is not specified */
+ void SetSourceName(const FText& InName = FText());
+
+ /** Callback for when the Add New Tag button is pressed */
+ FReply OnAddNewSourceButtonPressed();
+
+private:
+
+ /** The name of the next gameplay tag source to create */
+ TSharedPtr SourceNameTextBox;
+
+ /** Callback for when a new gameplay tag has been added to the INI files */
+ FOnGameplayTagSourceAdded OnGameplayTagSourceAdded;
+
+ /** Tracks if this widget should get keyboard focus */
+ bool bShouldGetKeyboardFocus;
+
+ FString DefaultNewName;
+};
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.cpp
index 7abb8fb79fc4..09e082fba98a 100644
--- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.cpp
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewGameplayTagWidget.cpp
@@ -4,7 +4,7 @@
#include "DetailLayoutBuilder.h"
#include "GameplayTagsSettings.h"
#include "GameplayTagsEditorModule.h"
-#include "SGameplayTagWidget.h"
+#include "GameplayTagsModule.h"
#include "Widgets/Input/SButton.h"
#define LOCTEXT_NAMESPACE "AddNewGameplayTagWidget"
@@ -26,6 +26,8 @@ void SAddNewGameplayTagWidget::Construct(const FArguments& InArgs)
OnGameplayTagAdded = InArgs._OnGameplayTagAdded;
PopulateTagSources();
+ IGameplayTagsModule::OnTagSettingsChanged.AddRaw(this, &SAddNewGameplayTagWidget::PopulateTagSources);
+
ChildSlot
[
SNew(SVerticalBox)
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewRestrictedGameplayTagWidget.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewRestrictedGameplayTagWidget.cpp
new file mode 100644
index 000000000000..5a3d7a1e3e22
--- /dev/null
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewRestrictedGameplayTagWidget.cpp
@@ -0,0 +1,361 @@
+// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
+
+#include "SAddNewRestrictedGameplayTagWidget.h"
+#include "DetailLayoutBuilder.h"
+#include "GameplayTagsSettings.h"
+#include "GameplayTagsEditorModule.h"
+#include "GameplayTagsModule.h"
+#include "SGameplayTagWidget.h"
+#include "Widgets/Input/SButton.h"
+#include "Widgets/Notifications/SNotificationList.h"
+#include "Framework/Notifications/NotificationManager.h"
+
+#define LOCTEXT_NAMESPACE "AddNewRestrictedGameplayTagWidget"
+
+void SAddNewRestrictedGameplayTagWidget::Construct(const FArguments& InArgs)
+{
+ FText HintText = LOCTEXT("NewTagNameHint", "X.Y.Z");
+ DefaultNewName = InArgs._NewRestrictedTagName;
+ if (DefaultNewName.IsEmpty() == false)
+ {
+ HintText = FText::FromString(DefaultNewName);
+ }
+
+
+ bAddingNewRestrictedTag = false;
+ bShouldGetKeyboardFocus = false;
+
+ OnRestrictedGameplayTagAdded = InArgs._OnRestrictedGameplayTagAdded;
+ PopulateTagSources();
+
+ IGameplayTagsModule::OnTagSettingsChanged.AddRaw(this, &SAddNewRestrictedGameplayTagWidget::PopulateTagSources);
+
+ ChildSlot
+ [
+ SNew(SVerticalBox)
+
+ // Restricted Tag Name
+ + SVerticalBox::Slot()
+ .AutoHeight()
+ .VAlign(VAlign_Top)
+ [
+ SNew(SHorizontalBox)
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 4.0f)
+ .AutoWidth()
+ [
+ SNew(STextBlock)
+ .Text(LOCTEXT("NewTagName", "Name:"))
+ ]
+
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 2.0f)
+ .FillWidth(1.0f)
+ .HAlign(HAlign_Right)
+ [
+ SAssignNew(TagNameTextBox, SEditableTextBox)
+ .MinDesiredWidth(240.0f)
+ .HintText(HintText)
+ .OnTextCommitted(this, &SAddNewRestrictedGameplayTagWidget::OnCommitNewTagName)
+ ]
+ ]
+
+ // Tag Comment
+ + SVerticalBox::Slot()
+ .AutoHeight()
+ .VAlign(VAlign_Top)
+ [
+ SNew(SHorizontalBox)
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 4.0f)
+ .AutoWidth()
+ [
+ SNew(STextBlock)
+ .Text(LOCTEXT("TagComment", "Comment:"))
+ ]
+
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 2.0f)
+ .FillWidth(1.0f)
+ .HAlign(HAlign_Right)
+ [
+ SAssignNew(TagCommentTextBox, SEditableTextBox)
+ .MinDesiredWidth(240.0f)
+ .HintText(LOCTEXT("TagCommentHint", "Comment"))
+ .OnTextCommitted(this, &SAddNewRestrictedGameplayTagWidget::OnCommitNewTagName)
+ ]
+ ]
+
+ + SVerticalBox::Slot()
+ .AutoHeight()
+ .VAlign(VAlign_Top)
+ [
+ SNew(SHorizontalBox)
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 4.0f)
+ .AutoWidth()
+ [
+ SNew(STextBlock)
+ .Text(LOCTEXT("AllowNonRestrictedChildren", "Allow non-restricted children:"))
+ ]
+
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 2.0f)
+ .FillWidth(1.0f)
+ .HAlign(HAlign_Right)
+ [
+ SAssignNew(AllowNonRestrictedChildrenCheckBox, SCheckBox)
+ ]
+ ]
+
+ // Tag Location
+ + SVerticalBox::Slot()
+ .AutoHeight()
+ .VAlign(VAlign_Top)
+ [
+ SNew(SHorizontalBox)
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 6.0f)
+ .AutoWidth()
+ [
+ SNew(STextBlock)
+ .Text(LOCTEXT("CreateTagSource", "Source:"))
+ ]
+
+ + SHorizontalBox::Slot()
+ .Padding(2.0f, 2.0f)
+ .FillWidth(1.0f)
+ .HAlign(HAlign_Right)
+ [
+ SAssignNew(TagSourcesComboBox, SComboBox >)
+ .OptionsSource(&RestrictedTagSources)
+ .OnGenerateWidget(this, &SAddNewRestrictedGameplayTagWidget::OnGenerateTagSourcesComboBox)
+ .ContentPadding(2.0f)
+ .Content()
+ [
+ SNew(STextBlock)
+ .Text(this, &SAddNewRestrictedGameplayTagWidget::CreateTagSourcesComboBoxContent)
+ .Font(IDetailLayoutBuilder::GetDetailFont())
+ ]
+ ]
+ ]
+
+ // Add Tag Button
+ +SVerticalBox::Slot()
+ .AutoHeight()
+ .VAlign(VAlign_Top)
+ .HAlign(HAlign_Center)
+ .Padding(8.0f)
+ [
+ SNew(SHorizontalBox)
+ + SHorizontalBox::Slot()
+ .AutoWidth()
+ [
+ SNew(SButton)
+ .Text(LOCTEXT("AddNew", "Add New Tag"))
+ .OnClicked(this, &SAddNewRestrictedGameplayTagWidget::OnAddNewTagButtonPressed)
+ ]
+ ]
+ ];
+
+ Reset();
+}
+
+void SAddNewRestrictedGameplayTagWidget::Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime )
+{
+ if (bShouldGetKeyboardFocus)
+ {
+ bShouldGetKeyboardFocus = false;
+ FSlateApplication::Get().SetKeyboardFocus(TagNameTextBox.ToSharedRef(), EFocusCause::SetDirectly);
+ }
+}
+
+void SAddNewRestrictedGameplayTagWidget::PopulateTagSources()
+{
+ UGameplayTagsManager& Manager = UGameplayTagsManager::Get();
+ RestrictedTagSources.Empty();
+
+ FName DefaultSource = FGameplayTagSource::GetDefaultName();
+
+ // Always ensure that the default source is first
+ RestrictedTagSources.Add( MakeShareable( new FName( DefaultSource ) ) );
+
+ TArray Sources;
+ Manager.GetRestrictedTagSources(Sources);
+
+ for (const FGameplayTagSource* Source : Sources)
+ {
+ if (Source != nullptr && Source->SourceName != DefaultSource)
+ {
+ RestrictedTagSources.Add(MakeShareable(new FName(Source->SourceName)));
+ }
+ }
+}
+
+void SAddNewRestrictedGameplayTagWidget::Reset()
+{
+ SetTagName();
+ SelectTagSource();
+ SetAllowNonRestrictedChildren();
+ TagCommentTextBox->SetText(FText());
+}
+
+void SAddNewRestrictedGameplayTagWidget::SetTagName(const FText& InName)
+{
+ TagNameTextBox->SetText(InName.IsEmpty() ? FText::FromString(DefaultNewName) : InName);
+}
+
+void SAddNewRestrictedGameplayTagWidget::SelectTagSource(const FName& InSource)
+{
+ // Attempt to find the location in our sources, otherwise just use the first one
+ int32 SourceIndex = 0;
+
+ if (!InSource.IsNone())
+ {
+ for (int32 Index = 0; Index < RestrictedTagSources.Num(); ++Index)
+ {
+ TSharedPtr Source = RestrictedTagSources[Index];
+
+ if (Source.IsValid() && *Source.Get() == InSource)
+ {
+ SourceIndex = Index;
+ break;
+ }
+ }
+ }
+
+ TagSourcesComboBox->SetSelectedItem(RestrictedTagSources[SourceIndex]);
+}
+
+void SAddNewRestrictedGameplayTagWidget::SetAllowNonRestrictedChildren(bool bInAllowNonRestrictedChildren)
+{
+ AllowNonRestrictedChildrenCheckBox->SetIsChecked(bInAllowNonRestrictedChildren ? ECheckBoxState::Checked : ECheckBoxState::Unchecked);
+}
+
+void SAddNewRestrictedGameplayTagWidget::OnCommitNewTagName(const FText& InText, ETextCommit::Type InCommitType)
+{
+ if (InCommitType == ETextCommit::OnEnter)
+ {
+ ValidateNewRestrictedTag();
+ }
+}
+
+FReply SAddNewRestrictedGameplayTagWidget::OnAddNewTagButtonPressed()
+{
+ ValidateNewRestrictedTag();
+ return FReply::Handled();
+}
+
+void SAddNewRestrictedGameplayTagWidget::AddSubtagFromParent(const FString& ParentTagName, const FName& ParentTagSource, bool bAllowNonRestrictedChildren)
+{
+ FText SubtagBaseName = !ParentTagName.IsEmpty() ? FText::Format(FText::FromString(TEXT("{0}.")), FText::FromString(ParentTagName)) : FText();
+
+ SetTagName(SubtagBaseName);
+ SelectTagSource(ParentTagSource);
+ SetAllowNonRestrictedChildren(bAllowNonRestrictedChildren);
+
+ bShouldGetKeyboardFocus = true;
+}
+
+void SAddNewRestrictedGameplayTagWidget::ValidateNewRestrictedTag()
+{
+ UGameplayTagsManager& Manager = UGameplayTagsManager::Get();
+
+ FString TagName = TagNameTextBox->GetText().ToString();
+ FString TagComment = TagCommentTextBox->GetText().ToString();
+ bool bAllowNonRestrictedChildren = AllowNonRestrictedChildrenCheckBox->IsChecked();
+ FName TagSource = *TagSourcesComboBox->GetSelectedItem().Get();
+
+ TArray TagSourceOwners;
+ Manager.GetOwnersForTagSource(TagSource.ToString(), TagSourceOwners);
+
+ bool bHasOwner = false;
+ for (const FString& Owner : TagSourceOwners)
+ {
+ if (!Owner.IsEmpty())
+ {
+ bHasOwner = true;
+ break;
+ }
+ }
+
+ if (bHasOwner)
+ {
+ FString StringToDisplay = TEXT("Do you have permission from ");
+ StringToDisplay.Append(TagSourceOwners[0]);
+ for (int Idx = 1; Idx < TagSourceOwners.Num(); ++Idx)
+ {
+ StringToDisplay.Append(TEXT(" or "));
+ StringToDisplay.Append(TagSourceOwners[Idx]);
+ }
+ StringToDisplay.Append(TEXT(" to modify "));
+ StringToDisplay.Append(TagSource.ToString());
+ StringToDisplay.Append(TEXT("?"));
+
+ FNotificationInfo Info(FText::FromString(StringToDisplay));
+ Info.ExpireDuration = 10.f;
+ Info.ButtonDetails.Add(FNotificationButtonInfo(LOCTEXT("RestrictedTagPopupButtonAccept", "Yes"), FText(), FSimpleDelegate::CreateSP(this, &SAddNewRestrictedGameplayTagWidget::CreateNewRestrictedGameplayTag), SNotificationItem::CS_None));
+ Info.ButtonDetails.Add(FNotificationButtonInfo(LOCTEXT("RestrictedTagPopupButtonReject", "No"), FText(), FSimpleDelegate::CreateSP(this, &SAddNewRestrictedGameplayTagWidget::CancelNewTag), SNotificationItem::CS_None));
+
+ AddRestrictedGameplayTagDialog = FSlateNotificationManager::Get().AddNotification(Info);
+ }
+ else
+ {
+ CreateNewRestrictedGameplayTag();
+ }
+}
+
+void SAddNewRestrictedGameplayTagWidget::CreateNewRestrictedGameplayTag()
+{
+ if (AddRestrictedGameplayTagDialog.IsValid())
+ {
+ AddRestrictedGameplayTagDialog->SetVisibility(EVisibility::Collapsed);
+ }
+
+ UGameplayTagsManager& Manager = UGameplayTagsManager::Get();
+
+ // Only support adding tags via ini file
+ if (Manager.ShouldImportTagsFromINI() == false)
+ {
+ return;
+ }
+
+ FString TagName = TagNameTextBox->GetText().ToString();
+ FString TagComment = TagCommentTextBox->GetText().ToString();
+ bool bAllowNonRestrictedChildren = AllowNonRestrictedChildrenCheckBox->IsChecked();
+ FName TagSource = *TagSourcesComboBox->GetSelectedItem().Get();
+
+ if (TagName.IsEmpty())
+ {
+ return;
+ }
+
+ // set bIsAddingNewTag, this guards against the window closing when it loses focus due to source control checking out a file
+ TGuardValue Guard(bAddingNewRestrictedTag, true);
+
+ IGameplayTagsEditorModule::Get().AddNewGameplayTagToINI(TagName, TagComment, TagSource, true, bAllowNonRestrictedChildren);
+
+ OnRestrictedGameplayTagAdded.ExecuteIfBound(TagName, TagComment, TagSource);
+
+ Reset();
+}
+
+void SAddNewRestrictedGameplayTagWidget::CancelNewTag()
+{
+ AddRestrictedGameplayTagDialog->SetVisibility(EVisibility::Collapsed);
+}
+
+TSharedRef SAddNewRestrictedGameplayTagWidget::OnGenerateTagSourcesComboBox(TSharedPtr InItem)
+{
+ return SNew(STextBlock)
+ .Text(FText::FromName(*InItem.Get()));
+}
+
+FText SAddNewRestrictedGameplayTagWidget::CreateTagSourcesComboBoxContent() const
+{
+ const bool bHasSelectedItem = TagSourcesComboBox.IsValid() && TagSourcesComboBox->GetSelectedItem().IsValid();
+
+ return bHasSelectedItem ? FText::FromName(*TagSourcesComboBox->GetSelectedItem().Get()) : LOCTEXT("NewTagLocationNotSelected", "Not selected");
+}
+
+#undef LOCTEXT_NAMESPACE
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewRestrictedGameplayTagWidget.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewRestrictedGameplayTagWidget.h
new file mode 100644
index 000000000000..f14a20b037cf
--- /dev/null
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SAddNewRestrictedGameplayTagWidget.h
@@ -0,0 +1,105 @@
+// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
+
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GameplayTagsManager.h"
+#include "Input/Reply.h"
+#include "Widgets/SWidget.h"
+#include "Widgets/SCompoundWidget.h"
+#include "Widgets/DeclarativeSyntaxSupport.h"
+#include "Widgets/Input/SEditableTextBox.h"
+#include "Widgets/Input/SComboBox.h"
+#include "Widgets/Input/SCheckBox.h"
+#include "Widgets/Notifications/SNotificationList.h"
+
+/** Widget allowing the user to create new restricted gameplay tags */
+class SAddNewRestrictedGameplayTagWidget : public SCompoundWidget
+{
+public:
+
+ DECLARE_DELEGATE_ThreeParams(FOnRestrictedGameplayTagAdded, const FString& /*TagName*/, const FString& /*TagComment*/, const FName& /*TagSource*/);
+
+ SLATE_BEGIN_ARGS(SAddNewRestrictedGameplayTagWidget)
+ : _NewRestrictedTagName(TEXT(""))
+ {}
+ SLATE_EVENT( FOnRestrictedGameplayTagAdded, OnRestrictedGameplayTagAdded ) // Callback for when a new tag is added
+ SLATE_ARGUMENT( FString, NewRestrictedTagName ) // String that will initially populate the New Tag Name field
+ SLATE_END_ARGS();
+
+ virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override;
+
+ void Construct( const FArguments& InArgs);
+
+ /** Returns true if we're currently attempting to add a new restricted gameplay tag to an INI file */
+ bool IsAddingNewRestrictedTag() const
+ {
+ return bAddingNewRestrictedTag;
+ }
+
+ /** Begins the process of adding a subtag to a parent tag */
+ void AddSubtagFromParent(const FString& ParentTagName, const FName& ParentTagSource, bool bAllowNonRestrictedChildren);
+
+ /** Resets all input fields */
+ void Reset();
+
+private:
+
+ /** Sets the name of the tag. Uses the default if the name is not specified */
+ void SetTagName(const FText& InName = FText());
+
+ /** Selects tag file location. Uses the default if the location is not specified */
+ void SelectTagSource(const FName& InSource = FName());
+
+ void SetAllowNonRestrictedChildren(bool bInAllowNonRestrictedChildren = false);
+
+ /** Creates a list of all INIs that gameplay tags can be added to */
+ void PopulateTagSources();
+
+ /** Callback for when Enter is pressed when modifying a tag's name or comment */
+ void OnCommitNewTagName(const FText& InText, ETextCommit::Type InCommitType);
+
+ /** Callback for when the Add New Tag button is pressed */
+ FReply OnAddNewTagButtonPressed();
+
+ void ValidateNewRestrictedTag();
+
+ /** Creates a new restricted gameplay tag and adds it to the INI files based on the widget's stored parameters */
+ void CreateNewRestrictedGameplayTag();
+
+ void CancelNewTag();
+
+ /** Populates the widget's combo box with all potential places where a gameplay tag can be stored */
+ TSharedRef OnGenerateTagSourcesComboBox(TSharedPtr InItem);
+
+ /** Creates the text displayed by the combo box when an option is selected */
+ FText CreateTagSourcesComboBoxContent() const;
+
+private:
+
+ /** All potential INI files where a gameplay tag can be stored */
+ TArray > RestrictedTagSources;
+
+ /** The name of the next gameplay tag to create */
+ TSharedPtr TagNameTextBox;
+
+ /** The comment to asign to the next gameplay tag to create*/
+ TSharedPtr TagCommentTextBox;
+
+ TSharedPtr AllowNonRestrictedChildrenCheckBox;
+
+ /** The INI file where the next restricted gameplay tag will be created */
+ TSharedPtr > > TagSourcesComboBox;
+
+ /** Callback for when a new restricted gameplay tag has been added to the INI files */
+ FOnRestrictedGameplayTagAdded OnRestrictedGameplayTagAdded;
+
+ bool bAddingNewRestrictedTag;
+
+ /** Tracks if this widget should get keyboard focus */
+ bool bShouldGetKeyboardFocus;
+
+ FString DefaultNewName;
+
+ TSharedPtr AddRestrictedGameplayTagDialog;
+};
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.cpp b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.cpp
index e3ab0e855c80..50993a36ab61 100644
--- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.cpp
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.cpp
@@ -25,6 +25,8 @@
#include "Layout/WidgetPath.h"
#include "Framework/Application/SlateApplication.h"
#include "SAddNewGameplayTagWidget.h"
+#include "SAddNewGameplayTagSourceWidget.h"
+#include "SAddNewRestrictedGameplayTagWidget.h"
#include "SRenameGameplayTagDialog.h"
#include "AssetData.h"
#include "AssetManagerEditorModule.h"
@@ -53,10 +55,25 @@ void SGameplayTagWidget::Construct(const FArguments& InArgs, const TArray= 0; --Idx)
+ {
+ if (!TagItems[Idx]->IsRestrictedGameplayTag())
+ {
+ TagItems.RemoveAtSwap(Idx);
+ }
+ }
+ }
+
// Tag the assets as transactional so they can support undo/redo
TArray ObjectsToMarkTransactional;
if (PropertyHandle.IsValid())
@@ -82,6 +99,8 @@ void SGameplayTagWidget::Construct(const FArguments& InArgs, const TArray InIte
return false;
}
+ if (bRestrictedTags && !InItem->IsRestrictedGameplayTag())
+ {
+ return false;
+ }
+
auto FilterChildrenCheck_r = ([=]()
{
TArray< TSharedPtr > Children = InItem->GetChildTagNodes();
@@ -323,27 +396,50 @@ TSharedRef SGameplayTagWidget::OnGenerateRow(TSharedPtrGetCompleteTagName();
- FString TagComment;
- FName TagSource;
-
- Manager.GetTagEditorData(TagName, TagComment, TagSource);
+ TSharedPtr Node = Manager.FindTagNode(TagName);
FString TooltipString = TagName.ToString();
- // Add Tag source in management mode
- if (GameplayTagUIMode == EGameplayTagUIMode::ManagementMode)
+ if (Node.IsValid())
{
- if (TagSource == NAME_None)
+ // Add Tag source if we're in management mode
+ if (GameplayTagUIMode == EGameplayTagUIMode::ManagementMode)
{
- TagSource = FName(TEXT("Implicit"));
+ FName TagSource;
+
+ if (Node->bIsExplicitTag)
+ {
+ TagSource = Node->SourceName;
+ }
+ else
+ {
+ TagSource = FName(TEXT("Implicit"));
+ }
+
+ TooltipString.Append(FString::Printf(TEXT(" (%s)"), *TagSource.ToString()));
}
- TooltipString.Append(FString::Printf(TEXT(" (%s)"), *TagSource.ToString()));
- }
+ // tag comments
+ if (!Node->DevComment.IsEmpty())
+ {
+ TooltipString.Append(FString::Printf(TEXT("\n\n%s"), *Node->DevComment));
+ }
- if (!TagComment.IsEmpty())
- {
- TooltipString.Append(FString::Printf(TEXT("\n\n%s"), *TagComment));
+ // info related to conflicts
+ if (Node->bDescendantHasConflict)
+ {
+ TooltipString.Append(TEXT("\n\nA tag that descends from this tag has a source conflict."));
+ }
+
+ if (Node->bAncestorHasConflict)
+ {
+ TooltipString.Append(TEXT("\n\nThis tag is descended from a tag that has a conflict. No operations can be performed on this tag until the conflict is resolved."));
+ }
+
+ if (Node->bNodeHasConflict)
+ {
+ TooltipString.Append(TEXT("\n\nThis tag comes from multiple sources. Tags may only have one source."));
+ }
}
TooltipText = FText::FromString(TooltipString);
@@ -379,9 +475,22 @@ TSharedRef SGameplayTagWidget::OnGenerateRow(TSharedPtrGetSimpleTagName()) )
+ .ColorAndOpacity(this, &SGameplayTagWidget::GetTagTextColour, InItem)
.Visibility( GameplayTagUIMode != EGameplayTagUIMode::SelectionMode ? EVisibility::Visible : EVisibility::Collapsed )
]
+ // Allows non-restricted children checkbox
+ +SHorizontalBox::Slot()
+ .AutoWidth()
+ .HAlign(HAlign_Right)
+ [
+ SNew(SCheckBox)
+ .ToolTipText(LOCTEXT("AllowsChildren", "Does this restricted tag allow non-restricted children"))
+ .OnCheckStateChanged(this, &SGameplayTagWidget::OnAllowChildrenTagCheckStatusChanged, InItem)
+ .IsChecked(this, &SGameplayTagWidget::IsAllowChildrenTagChecked, InItem)
+ .Visibility(this, &SGameplayTagWidget::DetermineAllowChildrenVisible, InItem)
+ ]
+
// Add Subtag
+SHorizontalBox::Slot()
.AutoWidth()
@@ -389,7 +498,7 @@ TSharedRef SGameplayTagWidget::OnGenerateRow(TSharedPtr Nod
}
}
+void SGameplayTagWidget::OnAllowChildrenTagCheckStatusChanged(ECheckBoxState NewCheckState, TSharedPtr NodeChanged)
+{
+ if (NewCheckState == ECheckBoxState::Checked)
+ {
+ NodeChanged->bAllowNonRestrictedChildren = true;
+ }
+ else if (NewCheckState == ECheckBoxState::Unchecked)
+ {
+ NodeChanged->bAllowNonRestrictedChildren = false;
+ }
+}
+
+ECheckBoxState SGameplayTagWidget::IsAllowChildrenTagChecked(TSharedPtr Node) const
+{
+ if (Node->GetAllowNonRestrictedChildren())
+ {
+ return ECheckBoxState::Checked;
+ }
+
+ return ECheckBoxState::Unchecked;
+}
+
+EVisibility SGameplayTagWidget::DetermineAllowChildrenVisible(TSharedPtr Node) const
+{
+ // We do not allow you to modify nodes that have a conflict or inherit from a node with a conflict
+ if (Node->bNodeHasConflict || Node->bAncestorHasConflict)
+ {
+ return EVisibility::Hidden;
+ }
+
+ if (bRestrictedTags)
+ {
+ return EVisibility::Visible;
+ }
+
+ return EVisibility::Collapsed;
+}
+
FReply SGameplayTagWidget::OnClearAllClicked()
{
FScopedTransaction Transaction( LOCTEXT("GameplayTagWidget_RemoveAllTags", "Remove All Gameplay Tags") );
@@ -619,6 +766,31 @@ FReply SGameplayTagWidget::OnClearAllClicked()
return FReply::Handled();
}
+FSlateColor SGameplayTagWidget::GetTagTextColour(TSharedPtr Node) const
+{
+ static const FLinearColor DefaultTextColour = FLinearColor::White;
+ static const FLinearColor DescendantConflictTextColour = FLinearColor(1.f, 0.65f, 0.f); // orange
+ static const FLinearColor NodeConflictTextColour = FLinearColor::Red;
+ static const FLinearColor AncestorConflictTextColour = FLinearColor(1.f, 1.f, 1.f, 0.5f);
+
+ if (Node->bNodeHasConflict)
+ {
+ return NodeConflictTextColour;
+ }
+
+ if (Node->bDescendantHasConflict)
+ {
+ return DescendantConflictTextColour;
+ }
+
+ if (Node->bAncestorHasConflict)
+ {
+ return AncestorConflictTextColour;
+ }
+
+ return DefaultTextColour;
+}
+
FReply SGameplayTagWidget::OnExpandAllClicked()
{
SetTagTreeItemExpansion(true);
@@ -640,8 +812,11 @@ FReply SGameplayTagWidget::OnAddSubtagClicked(TSharedPtr InTag
FString TagName = InTagNode->GetCompleteTagString();
FString TagComment;
FName TagSource;
+ bool bTagIsExplicit;
+ bool bTagIsRestricted;
+ bool bTagAllowsNonRestrictedChildren;
- Manager.GetTagEditorData(InTagNode->GetCompleteTagName(), TagComment, TagSource);
+ Manager.GetTagEditorData(InTagNode->GetCompleteTagName(), TagComment, TagSource, bTagIsExplicit, bTagIsRestricted, bTagAllowsNonRestrictedChildren);
if (AddNewTagWidget.IsValid())
{
@@ -662,6 +837,12 @@ TSharedRef SGameplayTagWidget::MakeTagActionsMenu(TSharedPtrIsRestrictedGameplayTag())
+ {
+ bShowManagement = false;
+ }
+
FMenuBuilder MenuBuilder(true, NULL);
// Rename
@@ -959,11 +1140,21 @@ EVisibility SGameplayTagWidget::DetermineExpandableUIVisibility() const
return EVisibility::Visible;
}
+EVisibility SGameplayTagWidget::DetermineAddNewSourceExpandableUIVisibility() const
+{
+ if (bRestrictedTags)
+ {
+ return EVisibility::Collapsed;
+ }
+
+ return DetermineExpandableUIVisibility();
+}
+
EVisibility SGameplayTagWidget::DetermineAddNewTagWidgetVisibility() const
{
UGameplayTagsManager& Manager = UGameplayTagsManager::Get();
- if ( !Manager.ShouldImportTagsFromINI() || !bAddTagSectionExpanded )
+ if ( !Manager.ShouldImportTagsFromINI() || !bAddTagSectionExpanded || bRestrictedTags )
{
// If we can't support adding tags from INI files, we should never see this widget
return EVisibility::Collapsed;
@@ -972,6 +1163,55 @@ EVisibility SGameplayTagWidget::DetermineAddNewTagWidgetVisibility() const
return EVisibility::Visible;
}
+EVisibility SGameplayTagWidget::DetermineAddNewRestrictedTagWidgetVisibility() const
+{
+ UGameplayTagsManager& Manager = UGameplayTagsManager::Get();
+
+ if (!Manager.ShouldImportTagsFromINI() || !bAddTagSectionExpanded || !bRestrictedTags)
+ {
+ // If we can't support adding tags from INI files, we should never see this widget
+ return EVisibility::Collapsed;
+ }
+
+ return EVisibility::Visible;
+}
+
+EVisibility SGameplayTagWidget::DetermineAddNewSourceWidgetVisibility() const
+{
+ UGameplayTagsManager& Manager = UGameplayTagsManager::Get();
+
+ if (!Manager.ShouldImportTagsFromINI() || !bAddSourceSectionExpanded || bRestrictedTags)
+ {
+ // If we can't support adding tags from INI files, we should never see this widget
+ return EVisibility::Collapsed;
+ }
+
+ return EVisibility::Visible;
+}
+
+EVisibility SGameplayTagWidget::DetermineAddNewSubTagWidgetVisibility(TSharedPtr Node) const
+{
+ EVisibility LocalVisibility = DetermineExpandableUIVisibility();
+ if (LocalVisibility != EVisibility::Visible)
+ {
+ return LocalVisibility;
+ }
+
+ // We do not allow you to add child tags under a conflict
+ if (Node->bNodeHasConflict || Node->bAncestorHasConflict)
+ {
+ return EVisibility::Hidden;
+ }
+
+ // show if we're dealing with restricted tags exclusively or restricted tags that allow non-restricted children
+ if (Node->GetAllowNonRestrictedChildren() || bRestrictedTags)
+ {
+ return EVisibility::Visible;
+ }
+
+ return EVisibility::Hidden;
+}
+
EVisibility SGameplayTagWidget::DetermineClearSelectionVisibility() const
{
return CanSelectTags() ? EVisibility::Visible : EVisibility::Collapsed;
@@ -997,6 +1237,16 @@ void SGameplayTagWidget::OnAddTagSectionExpansionStateChanged(ECheckBoxState New
bAddTagSectionExpanded = NewState == ECheckBoxState::Checked;
}
+ECheckBoxState SGameplayTagWidget::GetAddSourceSectionExpansionState() const
+{
+ return bAddSourceSectionExpanded ? ECheckBoxState::Checked : ECheckBoxState::Unchecked;
+}
+
+void SGameplayTagWidget::OnAddSourceSectionExpansionStateChanged(ECheckBoxState NewState)
+{
+ bAddSourceSectionExpanded = NewState == ECheckBoxState::Checked;
+}
+
void SGameplayTagWidget::RefreshOnNextTick()
{
bDelayRefresh = true;
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.h
index ffa0e5e799f7..57210a2fd906 100644
--- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.h
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Private/SGameplayTagWidget.h
@@ -17,6 +17,7 @@
class IPropertyHandle;
class SAddNewGameplayTagWidget;
+class SAddNewGameplayTagSourceWidget;
/** Determines the behavior of the gameplay tag UI depending on where it's used */
enum class EGameplayTagUIMode : uint8
@@ -43,6 +44,7 @@ public:
, _PropertyHandle( NULL )
, _GameplayTagUIMode( EGameplayTagUIMode::SelectionMode )
, _MaxHeight(260.0f)
+ , _RestrictedTags( false )
{}
SLATE_ARGUMENT( FString, Filter ) // Comma delimited string of tag root names to filter by
SLATE_ARGUMENT( FString, NewTagName ) // String that will initially populate the New Tag Name field
@@ -54,6 +56,7 @@ public:
SLATE_EVENT( FOnTagChanged, OnTagChanged ) // Called when a tag status changes
SLATE_ARGUMENT( EGameplayTagUIMode, GameplayTagUIMode ) // Determines behavior of the menu based on where it's used
SLATE_ARGUMENT( float, MaxHeight ) // caps the height of the gameplay tag tree
+ SLATE_ARGUMENT( bool, RestrictedTags ) // if we are dealing with restricted tags or regular gameplay tags
SLATE_END_ARGS()
/** Simple struct holding a tag container and its owner for generic re-use of the widget */
@@ -118,9 +121,15 @@ private:
/** Tracks if the Add Tag UI is expanded */
bool bAddTagSectionExpanded;
+ /** Tracks if the Add Source UI is expanded */
+ bool bAddSourceSectionExpanded;
+
/** If true, refreshes tags on the next frame */
bool bDelayRefresh;
+ /** If true, this widget is displaying restricted tags; if false this widget displays regular gameplay tags. */
+ bool bRestrictedTags;
+
/** The maximum height of the gameplay tag tree. If 0, the height is unbound. */
float MaxHeight;
@@ -139,6 +148,12 @@ private:
/** The widget that controls how new gameplay tags are added to the config files */
TSharedPtr AddNewTagWidget;
+ /** The widget that controls how new restricted gameplay tags are added to the config files */
+ TSharedPtr AddNewRestrictedTagWidget;
+
+ /** The widget that controls how new gameplay tag source files are added */
+ TSharedPtr AddNewTagSourceWidget;
+
/** Allows for the user to find a specific gameplay tag in the tree */
TSharedPtr SearchTagBox;
@@ -188,6 +203,26 @@ private:
*/
ECheckBoxState IsTagChecked(TSharedPtr Node) const;
+ /**
+ * Called via delegate when the status of the allow non-restricted children check box in a row changes
+ *
+ * @param NewCheckState New check box state
+ * @param NodeChanged Node that was checked/unchecked
+ */
+ void OnAllowChildrenTagCheckStatusChanged(ECheckBoxState NewCheckState, TSharedPtr NodeChanged);
+
+ /**
+ * Called via delegate to determine the non-restricted children checkbox state of the specified node
+ *
+ * @param Node Node to find the non-restricted children checkbox state of
+ *
+ * @return Non-restricted children heckbox state of the specified node
+ */
+ ECheckBoxState IsAllowChildrenTagChecked(TSharedPtr Node) const;
+
+ /** Helper function to determine the visibility of the checkbox for allowing non-restricted children of restricted gameplay tags */
+ EVisibility DetermineAllowChildrenVisible(TSharedPtr Node) const;
+
/**
* Helper function called when the specified node is checked
*
@@ -210,6 +245,15 @@ private:
*/
void UncheckChildren(TSharedPtr NodeUnchecked, FGameplayTagContainer& EditableContainer);
+ /**
+ * Called via delegate to determine the text colour of the specified node
+ *
+ * @param Node Node to find the colour of
+ *
+ * @return Text colour of the specified node
+ */
+ FSlateColor GetTagTextColour(TSharedPtr Node) const;
+
/** Called when the user clicks the "Clear All" button; Clears all tags */
FReply OnClearAllClicked();
@@ -246,9 +290,21 @@ private:
/** Helper function to determine the visibility of the expandable UI controls */
EVisibility DetermineExpandableUIVisibility() const;
+ /** Helper function to determine the visibility of the add new source expandable UI controls */
+ EVisibility DetermineAddNewSourceExpandableUIVisibility() const;
+
/** Helper function to determine the visibility of the Add New Tag widget */
EVisibility DetermineAddNewTagWidgetVisibility() const;
+ /** Helper function to determine the visibility of the Add New Tag widget */
+ EVisibility DetermineAddNewRestrictedTagWidgetVisibility() const;
+
+ /** Helper function to determine the visibility of the Add New Tag Source widget */
+ EVisibility DetermineAddNewSourceWidgetVisibility() const;
+
+ /** Helper function to determine the visibility of the Add New Subtag widget */
+ EVisibility DetermineAddNewSubTagWidgetVisibility(TSharedPtr Node) const;
+
/** Helper function to determine the visibility of the Clear Selection button */
EVisibility DetermineClearSelectionVisibility() const;
@@ -288,6 +344,12 @@ private:
/** Callback for when the state of the expandable UI section changes */
void OnAddTagSectionExpansionStateChanged(ECheckBoxState NewState);
+ /** Determines if the expandable UI that contains the Add New Tag Source widget should be expanded or collapsed */
+ ECheckBoxState GetAddSourceSectionExpansionState() const;
+
+ /** Callback for when the state of the expandable tag source UI section changes */
+ void OnAddSourceSectionExpansionStateChanged(ECheckBoxState NewState);
+
void SetContainer(FGameplayTagContainer* OriginalContainer, FGameplayTagContainer* EditedContainer, UObject* OwnerObj);
/** Opens a dialog window to rename the selected tag */
diff --git a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Public/GameplayTagsEditorModule.h b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Public/GameplayTagsEditorModule.h
index 17ff165a7cfc..ed5ef5394e58 100644
--- a/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Public/GameplayTagsEditorModule.h
+++ b/Engine/Plugins/Editor/GameplayTagsEditor/Source/GameplayTagsEditor/Public/GameplayTagsEditorModule.h
@@ -38,7 +38,7 @@ public:
}
/** Tries to add a new gameplay tag to the ini lists */
- GAMEPLAYTAGSEDITOR_API virtual bool AddNewGameplayTagToINI(const FString& NewTag, const FString& Comment = TEXT(""), FName TagSourceName = NAME_None) = 0;
+ GAMEPLAYTAGSEDITOR_API virtual bool AddNewGameplayTagToINI(const FString& NewTag, const FString& Comment = TEXT(""), FName TagSourceName = NAME_None, bool bIsRestrictedTag = false, bool bAllowNonRestrictedChildren = true) = 0;
/** Tries to delete a tag from the library. This will pop up special UI or error messages as needed. It will also delete redirectors if that is specified. */
GAMEPLAYTAGSEDITOR_API virtual bool DeleteTagFromINI(const FString& TagToDelete) = 0;
@@ -52,6 +52,11 @@ public:
/** This is public so that child structs of FGameplayTag can use the details customization */
struct GAMEPLAYTAGSEDITOR_API FGameplayTagCustomizationPublic
+{
+ static TSharedRef MakeInstance();
+};
+
+struct GAMEPLAYTAGSEDITOR_API FRestrictedGameplayTagCustomizationPublic
{
static TSharedRef MakeInstance();
};
\ No newline at end of file
diff --git a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/PropertyHelpers.cpp b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/PropertyHelpers.cpp
index 050060a02c6a..131510523ae1 100644
--- a/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/PropertyHelpers.cpp
+++ b/Engine/Plugins/Editor/USDImporter/Source/USDImporter/Private/PropertyHelpers.cpp
@@ -27,7 +27,7 @@ namespace PropertyHelpers
{
TCHAR NumberBuffer[11];
FMemory::Memcpy(NumberBuffer, &PropertyName[OpenIndex + 1], sizeof(TCHAR) * NumberLength);
- LexicalConversion::FromString(PropertyAndIndex.ArrayIndex, NumberBuffer);
+ LexFromString(PropertyAndIndex.ArrayIndex, NumberBuffer);
}
}
diff --git a/Engine/Plugins/Experimental/PlatformCrypto/Source/PlatformCrypto/PlatformCrypto.Build.cs b/Engine/Plugins/Experimental/PlatformCrypto/Source/PlatformCrypto/PlatformCrypto.Build.cs
index 41cdb677f371..83cfe4f9643f 100644
--- a/Engine/Plugins/Experimental/PlatformCrypto/Source/PlatformCrypto/PlatformCrypto.Build.cs
+++ b/Engine/Plugins/Experimental/PlatformCrypto/Source/PlatformCrypto/PlatformCrypto.Build.cs
@@ -68,4 +68,4 @@ namespace UnrealBuildTool.Rules
}
}
}
-}
+}
\ No newline at end of file
diff --git a/Engine/Plugins/Experimental/PlatformCrypto/Source/PlatformCrypto/Public/IPlatformCrypto.h b/Engine/Plugins/Experimental/PlatformCrypto/Source/PlatformCrypto/Public/IPlatformCrypto.h
index 753757894ad4..f038fdc06971 100644
--- a/Engine/Plugins/Experimental/PlatformCrypto/Source/PlatformCrypto/Public/IPlatformCrypto.h
+++ b/Engine/Plugins/Experimental/PlatformCrypto/Source/PlatformCrypto/Public/IPlatformCrypto.h
@@ -23,7 +23,15 @@ public:
*/
static inline IPlatformCrypto& Get()
{
- return FModuleManager::LoadModuleChecked< IPlatformCrypto >( "PlatformCrypto" );
+ // Check whether the module is already loaded first. This allows Get() to be called on non-game threads.
+ // LoadModuleChecked is not non-game-thread-safe.
+ IPlatformCrypto* ModulePtr = FModuleManager::GetModulePtr("PlatformCrypto");
+ if (ModulePtr)
+ {
+ return *ModulePtr;
+ }
+
+ return FModuleManager::LoadModuleChecked("PlatformCrypto");
}
/**
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/ProxyLODPlugin.uplugin b/Engine/Plugins/Experimental/ProxyLODPlugin/ProxyLODPlugin.uplugin
index 03cc5c027d98..3ce3d1f4c427 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/ProxyLODPlugin.uplugin
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/ProxyLODPlugin.uplugin
@@ -10,7 +10,7 @@
"DocsURL" : "",
"MarketplaceURL" : "",
"SupportURL" : "",
- "EnabledByDefault" : false,
+ "EnabledByDefault" : true,
"CanContainContent" : false,
"IsBetaVersion" : true,
"Installed" : false,
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMaterialTransferUtilities.cpp b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMaterialTransferUtilities.cpp
index a0318e1b59ba..b4651a011513 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMaterialTransferUtilities.cpp
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMaterialTransferUtilities.cpp
@@ -168,8 +168,9 @@ ProxyLOD::FSrcDataGrid::Ptr ProxyLOD::CreateCorrespondence( const FRawMeshArrayA
const auto& Indices = ReducedMesh.Indices;
const auto& Points = ReducedMesh.Points;
- const auto& Normal = ReducedMesh.Normal;
+ const auto& Normal = (ReducedMesh.TransferNormal.Num() == 0) ? ReducedMesh.Normal : ReducedMesh.TransferNormal;
+ checkSlow(Normal.Num() == Points.Num());
// Iterate over the the UVGrid.
@@ -183,8 +184,13 @@ ProxyLOD::FSrcDataGrid::Ptr ProxyLOD::CreateCorrespondence( const FRawMeshArrayA
{
const auto& TexelData = UVGrid(i, j);
ProxyLOD::FSrcMeshData& TargetTexel = TargetGrid(i, j);
+
+ // initialize with values that will be over-written if we
+ // can create a correspondence with the source mesh for this texel.
+
TargetTexel.MaterialId = -1;
+ // This texel is associated with a triangle on the target geometry.
if (TexelData.TriangleId > -1)
{
const uint32 TriangleId = TexelData.TriangleId;
@@ -403,7 +409,10 @@ ProxyLOD::FSrcDataGrid::Ptr ProxyLOD::CreateCorrespondence( const openvdb::Int32
const auto& Indices = ReducedMesh.Indices;
const auto& Points = ReducedMesh.Points;
- const auto& Normal = ReducedMesh.Normal;
+ const auto& Normal = (ReducedMesh.TransferNormal.Num() == 0) ? ReducedMesh.Normal : ReducedMesh.TransferNormal;
+
+ checkSlow(Normal.Num() == Points.Num());
+
// Iterate over the the UVGrid.
@@ -598,7 +607,7 @@ namespace
{
template
- void TransferMaterial(const ProxyLOD::FSrcDataGrid& CorrespondenceGrid, const ProxyLOD::FRasterGrid& UVGrid, const TArray& InputMaterials, TArray& SamplesBuffer)
+ void TransferMaterial(const ProxyLOD::FSrcDataGrid& CorrespondenceGrid, const ProxyLOD::FRasterGrid& UVGrid, const TArray& InputMaterials, TArray& SamplesBuffer, const FLinearColor DefaultColor = FLinearColor(0., 0., 0., 0.))
{
checkSlow(CorrespondenceGrid.Size() == UVGrid.Size());
@@ -609,10 +618,11 @@ namespace
// Init buffer to zero color
ProxyLOD::Parallel_For(ProxyLOD::FIntRange(0, BufferSize),
- [&SamplesBuffer](const ProxyLOD::FIntRange& Range)
+ [&SamplesBuffer, DefaultColor](const ProxyLOD::FIntRange& Range)
{
+ const float MinFloat = std::numeric_limits::lowest();
FLinearColor* Data = SamplesBuffer.GetData();
- for (int32 i = Range.begin(), I = Range.end(); i < I; ++i) Data[i] = FLinearColor(0.f, 0.f, 0.f, 0.f);
+ for (int32 i = Range.begin(), I = Range.end(); i < I; ++i) Data[i] = DefaultColor;
});
@@ -622,7 +632,7 @@ namespace
[&](const ProxyLOD::FIntRange& Range)
{
- const FColor EmptySrcColor(0, 0, 255);
+ const FColor EmptySrcColor = FColor::Black;
auto GetColorFromBuffer = [](const FIntPoint& Size, const TArray& Buffer, const FIntPoint& ij)->FLinearColor
{
@@ -845,7 +855,7 @@ namespace
* NB: It is assumed that the SuperSample Grid is a multiple of the OutBuffer Grid. I.e. an integer number of super sample
* texels correspond to each result texel
*/
- void SparseDownSampleColor(const ProxyLOD::TGridWrapper& SuperSampleGrid, ProxyLOD::FLinearColorGrid& OutGrid)
+ void SparseDownSampleColor(const ProxyLOD::TGridWrapper& SuperSampleGrid, ProxyLOD::FLinearColorGrid& OutGrid, const FLinearColor DefaultColor = FLinearColor(0., 0., 0., 0.))
{
FIntPoint SuperSampleSize = SuperSampleGrid.Size();
FIntPoint ResultSize = OutGrid.Size();
@@ -923,6 +933,10 @@ namespace
ResultColor *= LumaCorrection;
}
}
+ else
+ {
+ ResultColor = DefaultColor;
+ }
// write it into the buffer
ResultBuffer[i + j * ResultSize.X] = ResultColor;
@@ -1508,7 +1522,7 @@ namespace
void TMapFlattenMaterial(const FRawMesh& DstRawMesh, const FRawMeshArrayAdapter& SrcMeshAdapter,
const ProxyLOD::FSrcDataGrid& SuperSampledCorrespondenceGrid,
const ProxyLOD::FRasterGrid& SuperSampledDstUVGrid, const ProxyLOD::FRasterGrid& DstUVGrid,
- const TArray& InputMaterials, FFlattenMaterial& OutMaterial)
+ const TArray& InputMaterials, FFlattenMaterial& OutMaterial, const FColor DefaultColor = FColor::Black)
{
const FIntPoint OutSize = OutMaterial.GetPropertySize(PropertyType);
@@ -1549,8 +1563,12 @@ namespace
}
else if (PropertyType == EFlattenMaterialProperties::Diffuse)
{
+ // The base color to use when ray-based transfer can't find any source geometry. This happens most when
+ // using gap filling to close doors and windows.
+ const FLinearColor UnresolvedColor(DefaultColor);
+
TArray SuperSampledMaterial;
- TransferMaterial(SuperSampledCorrespondenceGrid, SuperSampledDstUVGrid, InputMaterials, SuperSampledMaterial);
+ TransferMaterial(SuperSampledCorrespondenceGrid, SuperSampledDstUVGrid, InputMaterials, SuperSampledMaterial, UnresolvedColor);
// Preserve the average luma when down sampling color.
ProxyLOD::TGridWrapper SuperSampleGrid(SuperSampledMaterial, SuperSampledDstUVGrid.Size());
@@ -1670,12 +1688,13 @@ void MapFlattenMaterial(const EFlattenMaterialProperties PropertyType,
const ProxyLOD::FRasterGrid& SuperSampledDstUVGrid,
const ProxyLOD::FRasterGrid& DstUVGrid,
const TArray& InputMaterials,
+ const FColor UnresolvedSrcColor,
FFlattenMaterial& OutMaterial)
{
switch (PropertyType)
{
case EFlattenMaterialProperties::Diffuse:
- TMapFlattenMaterial(DstRawMesh, SrcMeshAdapter, SuperSampledCorrespondenceGrid, SuperSampledDstUVGrid, DstUVGrid, InputMaterials, OutMaterial);
+ TMapFlattenMaterial(DstRawMesh, SrcMeshAdapter, SuperSampledCorrespondenceGrid, SuperSampledDstUVGrid, DstUVGrid, InputMaterials, OutMaterial, UnresolvedSrcColor);
break;
case EFlattenMaterialProperties::Specular:
TMapFlattenMaterial(DstRawMesh, SrcMeshAdapter, SuperSampledCorrespondenceGrid, SuperSampledDstUVGrid, DstUVGrid, InputMaterials, OutMaterial);
@@ -1708,7 +1727,8 @@ void ProxyLOD::MapFlattenMaterials(const FRawMesh& DstRawMesh, const FRawMeshArr
const ProxyLOD::FSrcDataGrid& SuperSampledCorrespondenceGrid,
const ProxyLOD::FRasterGrid& SuperSampledDstUVGrid,
const ProxyLOD::FRasterGrid& DstUVGrid,
- const TArray& InputMaterials,
+ const TArray& InputMaterials,
+ const FColor UnresolvedSrcColor,
FFlattenMaterial& OutMaterial)
{
@@ -1719,12 +1739,12 @@ void ProxyLOD::MapFlattenMaterials(const FRawMesh& DstRawMesh, const FRawMeshArr
// NB: The MaterialProperty is captured by value
- auto MapTask = [MaterialProperty, &DstRawMesh, &SrcMeshAdapter, &SuperSampledCorrespondenceGrid, &SuperSampledDstUVGrid, &DstUVGrid, &InputMaterials, &OutMaterial]
+ auto MapTask = [MaterialProperty, &DstRawMesh, &SrcMeshAdapter, &SuperSampledCorrespondenceGrid, &SuperSampledDstUVGrid, &DstUVGrid, &InputMaterials, UnresolvedSrcColor, &OutMaterial]
()
{
// This is also threaded internally.
- MapFlattenMaterial(MaterialProperty, DstRawMesh, SrcMeshAdapter, SuperSampledCorrespondenceGrid, SuperSampledDstUVGrid, DstUVGrid, InputMaterials, OutMaterial);
+ MapFlattenMaterial(MaterialProperty, DstRawMesh, SrcMeshAdapter, SuperSampledCorrespondenceGrid, SuperSampledDstUVGrid, DstUVGrid, InputMaterials, UnresolvedSrcColor, OutMaterial);
};
// enqueue the task with the task manager.
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMaterialTransferUtilities.h b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMaterialTransferUtilities.h
index 64cef3c7c626..5db99547c7a9 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMaterialTransferUtilities.h
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMaterialTransferUtilities.h
@@ -93,6 +93,8 @@ namespace ProxyLOD
* ( of the Simplified Geometry) to positions on the Simplified Geometry.
* @param InMaterials Array of flattened materials corresponding to the various meshes in the
* Src geometry.
+ * @param UnresolvedSrcColor Base color to be used when the src geometry can't be identified (e.g. regions where
+ * gap filling has closed doors and windows)
* @param OutMaterials Flattened materials for the Simplified Geometry.
*
* Map Diffuse, Specular, Metallic, Roughness, Normal, Emissive, Opacity to the correct materials.
@@ -104,6 +106,7 @@ namespace ProxyLOD
const ProxyLOD::FRasterGrid& SuperSampledDstUVGrid,
const ProxyLOD::FRasterGrid& DstUVGrid,
const TArray& InMaterials,
+ const FColor UnresolvedSrcColor,
FFlattenMaterial& OutMaterial);
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshConvertUtils.cpp b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshConvertUtils.cpp
index ac6a3e82126f..d56a9ad3fbc4 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshConvertUtils.cpp
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshConvertUtils.cpp
@@ -25,7 +25,7 @@ void ProxyLOD::MixedPolyMeshToRawMesh(const FMixedPolyMesh& SimpleMesh, FRawMesh
ProxyLOD::Parallel_For(ProxyLOD::FUIntRange(0, DstNumVerts),
[&SimpleMesh, &DstRawMesh](const ProxyLOD::FUIntRange& Range)
{
- // @todo DJH tbb::ProxyLOD::Parallel_For
+
for (uint32 i = Range.begin(), I = Range.end(); i < I; ++i)
{
const openvdb::Vec3s& Vertex = SimpleMesh.Points[i];
@@ -101,7 +101,7 @@ void ProxyLOD::MixedPolyMeshToRawMesh(const FMixedPolyMesh& SimpleMesh, FRawMesh
// Generate Tangent-Space
- // djh: adding default values for now
+ // NB: adding default values for now
ProxyLOD::Parallel_For(ProxyLOD::FUIntRange(0, DstNumIndexes), [&DstRawMesh](const ProxyLOD::FUIntRange& Range)
{
for (uint32 i = Range.begin(), I = Range.end(); i < I; ++i)
@@ -171,9 +171,10 @@ void ProxyLOD::AOSMeshToRawMesh(const FAOSMesh& AOSMesh, FRawMesh& OutRawMesh)
ProxyLOD::Parallel_For(ProxyLOD::FUIntRange(0, DstNumIndexes),
[&AOSMesh, &WedgeIndices](const ProxyLOD::FUIntRange& Range)
{
+ const auto& AOSIndexes = AOSMesh.Indexes;
for (uint32 i = Range.begin(), I = Range.end(); i < I; ++i)
{
- WedgeIndices[i] = AOSMesh.Indexes[i];
+ WedgeIndices[i] = AOSIndexes[i];
}
});
@@ -187,7 +188,7 @@ void ProxyLOD::AOSMeshToRawMesh(const FAOSMesh& AOSMesh, FRawMesh& OutRawMesh)
ResizeArray(OutRawMesh.WedgeTangentY, DstNumIndexes);
// Generate Tangent-Space
- // djh: adding default values for now
+ // NB: adding default values for now
ProxyLOD::Parallel_For(ProxyLOD::FUIntRange(0, DstNumIndexes), [&OutRawMesh](const ProxyLOD::FUIntRange& Range)
{
for (uint32 i = Range.begin(), I = Range.end(); i < I; ++i)
@@ -357,7 +358,7 @@ void ProxyLOD::VertexDataMeshToRawMesh(const FVertexDataMesh& SrcVertexDataMesh,
}
}
- // DJH Testing.
+
// Is the handedness the same for all verts on a given face?
{
const uint32 DstNumTris = DstNumIndexes / 3;
@@ -429,7 +430,7 @@ void ProxyLOD::VertexDataMeshToRawMesh(const FVertexDataMesh& SrcVertexDataMesh,
}
}
#if 0
- // DJH
+
// Testing with the handedness
for (uint32 i = 0; i < DstNumIndexes; ++i)
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshParameterization.cpp b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshParameterization.cpp
index cbacc2081b6a..945b0d0c8abf 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshParameterization.cpp
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshParameterization.cpp
@@ -10,8 +10,6 @@
#include "ProxyLODMeshUtilities.h"
-
-
bool ProxyLOD::GenerateUVs(FVertexDataMesh& InOutMesh, const FTextureAtlasDesc& TextureAtlasDesc, const bool VertexColorParts)
{
@@ -48,7 +46,8 @@ bool ProxyLOD::GenerateUVs(FVertexDataMesh& InOutMesh, const FTextureAtlasDesc&
// Let the polys in the partitions stretch some.. 1.f will let it stretch freely
- const float MaxStretch = 0.125f;
+ const float MaxStretch = 0.125f; // Question. Does this override the pIMT?
+
// Size of the texture atlas
@@ -72,7 +71,16 @@ bool ProxyLOD::GenerateUVs(FVertexDataMesh& InOutMesh, const FTextureAtlasDesc&
// the normals, but that resulted in some large planar regions being really compressed in the
// UV chart.
- float * pIMTArray = NULL;
+ float * pIMTArray = new float[NumFaces * 3];
+ for (int32 f = 0; f < NumFaces; ++f)
+ {
+ int32 offset = 3 * f;
+ {
+ pIMTArray[offset ] = 1.f;
+ pIMTArray[offset + 1] = 0.f;
+ pIMTArray[offset + 2] = 1.f;
+ }
+ }
HRESULT hr = DirectX::UVAtlasCreate(Pos, NumVerts,
indices, DXGI_FORMAT_R32_UINT, NumFaces,
@@ -85,6 +93,9 @@ bool ProxyLOD::GenerateUVs(FVertexDataMesh& InOutMesh, const FTextureAtlasDesc&
if (FAILED(hr)) return false;
+ if (pIMTArray) delete[] pIMTArray;
+
+
// testing
check(ib.size() / sizeof(uint32) == NumFaces * 3);
check(facePartitioning.size() == NumFaces);
@@ -147,6 +158,21 @@ bool ProxyLOD::GenerateUVs(FVertexDataMesh& InOutMesh, const FTextureAtlasDesc&
});
+ // Update the transfer normals
+ TaskGroup.Run([&]()
+ {
+ const size_t NumNewVerts = vb.size();
+ TArray NewTransferNormalsArray;
+ ResizeArray(NewTransferNormalsArray, NumNewVerts);
+
+ // re-order the verts
+ DirectX::UVAtlasApplyRemap(InOutMesh.TransferNormal.GetData(), sizeof(FVector), NumVerts, NumNewVerts, vertexRemapArray.data(), NewTransferNormalsArray.GetData());
+
+ // swap the data into the raw mesh
+ Swap(NewTransferNormalsArray, InOutMesh.TransferNormal);
+
+ });
+
// Update the tangents
TaskGroup.Run([&]()
{
@@ -253,53 +279,28 @@ void ProxyLOD::GenerateAdjacency(const FRawMesh& RawMesh, std::vector& A
bool ProxyLOD::GenerateAdjacenyAndCleanMesh(FVertexDataMesh& InOutMesh, std::vector& Adjacency)
{
- GenerateAdjacency(InOutMesh, Adjacency);
+
std::vector dupVerts;
- HRESULT hr = DirectX::Clean(InOutMesh.Indices.GetData(), InOutMesh.Indices.Num() / 3, InOutMesh.Points.Num(), Adjacency.data(), NULL, dupVerts, true /*break bowties*/);
+
uint32 CleanCount = 0;
- while (dupVerts.size() != 0 && CleanCount < 4)
+ while (CleanCount == 0 || (dupVerts.size() != 0 && CleanCount < 5))
{
CleanCount++;
- // add the duplicated verts
- uint32 NumDup = dupVerts.size();
- uint32 Offset = InOutMesh.Points.AddUninitialized(NumDup);
+ // Rebuild the adjacency.
+ Adjacency.clear();
+ GenerateAdjacency(InOutMesh, Adjacency);
- for (uint32 d = 0; d < NumDup; ++d)
- {
- InOutMesh.Points[Offset + d] = InOutMesh.Points[dupVerts[d]];
- }
+ dupVerts.clear();
+ HRESULT hr = DirectX::Clean(InOutMesh.Indices.GetData(), InOutMesh.Indices.Num() / 3, InOutMesh.Points.Num(), Adjacency.data(), NULL, dupVerts, true /*break bowties*/);
- // optionally copy the tangent plane.
- if (InOutMesh.Normal.Num() == Offset)
- {
- InOutMesh.Normal.AddUninitialized(NumDup);
- for (uint32 d = 0; d < NumDup; ++d)
- {
- InOutMesh.Normal[Offset + d] = InOutMesh.Normal[dupVerts[d]];
- }
- }
- if (InOutMesh.Tangent.Num() == Offset)
- {
- InOutMesh.Tangent.AddUninitialized(NumDup);
- for (uint32 d = 0; d < NumDup; ++d)
- {
- InOutMesh.Tangent[Offset + d] = InOutMesh.Tangent[dupVerts[d]];
- }
- }
- if (InOutMesh.BiTangent.Num() == Offset)
- {
- InOutMesh.BiTangent.AddUninitialized(NumDup);
- for (uint32 d = 0; d < NumDup; ++d)
- {
- InOutMesh.BiTangent[Offset + d] = InOutMesh.BiTangent[dupVerts[d]];
- }
- }
+ SplitVertices(InOutMesh, dupVerts);
+ uint32 Offset = InOutMesh.Points.Num();
// spatially separate bowties
for (int32 f = 0; f < InOutMesh.Indices.Num() / 3; ++f)
@@ -326,16 +327,8 @@ bool ProxyLOD::GenerateAdjacenyAndCleanMesh(FVertexDataMesh& InOutMesh, std::vec
}
}
}
-
-
- // Rebuild the adjacency.
- Adjacency.clear();
- GenerateAdjacency(InOutMesh, Adjacency);
-
- dupVerts.clear();
- hr = DirectX::Clean(InOutMesh.Indices.GetData(), InOutMesh.Indices.Num() / 3, InOutMesh.Points.Num(), Adjacency.data(), NULL, dupVerts, true /*break bowties*/);
-
}
return (dupVerts.size() == 0);
+
}
\ No newline at end of file
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.cpp b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.cpp
index 42a06def96cb..82ae49714344 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.cpp
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.cpp
@@ -1,11 +1,14 @@
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "ProxyLODMeshSDFConversions.h"
+#include "ProxyLODMeshConvertUtils.h"
#include "CoreMinimal.h"
#include // for MeshToVolume
+#include // for csgUnion
+
//#include
@@ -51,3 +54,207 @@ bool ProxyLOD::MeshArrayToSDFVolume(const FRawMeshArrayAdapter& MeshAdapter, ope
return success;
}
+
+
+bool ProxyLOD::MeshArrayToSDFVolume(const FRawMeshAdapter& MeshAdapter, openvdb::FloatGrid::Ptr& SDFGrid, openvdb::Int32Grid* PolyIndexGrid)
+{
+
+ bool success = true;
+ try
+ {
+ const float HalfBandWidth = 2.f;
+ int Flags = 0;
+ SDFGrid = openvdb::tools::meshToVolume(MeshAdapter, MeshAdapter.GetTransform(), HalfBandWidth /*exterior*/, HalfBandWidth/*interior*/, Flags, PolyIndexGrid);
+
+ // reduce memory footprint, increase the spareness.
+
+ openvdb::tools::pruneLevelSet(SDFGrid->tree(), HalfBandWidth, -HalfBandWidth);
+ }
+ catch (std::bad_alloc&)
+ {
+ success = false;
+ if (SDFGrid)
+ {
+ SDFGrid->tree().clear(); // free any memory held in the smart pointers in the grid
+ }
+ if (PolyIndexGrid)
+ {
+ PolyIndexGrid->clear();
+ }
+ }
+ return success;
+}
+
+
+/**
+* Generate a new SDF (with narrow band thickness of 2) that represents moving the zero crossing
+* the specified distance in either the positive or negative normal direction.
+*
+* NB: This will fail if the offset is greater than 2 voxels.
+
+*
+* @param InSDFVolume SDF grid with assumed narrow band of 2
+* @param WSOffset World Space Distance to offset the zero. This should be in the range -2dx : 2dx.
+* where dx is the input grid voxel size
+* @param ResultVoxelSize The voxel size used in the resulting grid.
+*
+* @return A new SDF that represents a dilation or erosion (expansion or contraction) of the original SDF
+*/
+static openvdb::FloatGrid::Ptr OffsetSDF(const openvdb::FloatGrid::Ptr InSDFVolume, const double WSOffset, const double ResultVolexSize)
+{
+ // Extract the iso-surface with offset DilationInVoxels.
+
+ // The voxel size in world space units : taking the first element is okay, since the voxels are square.
+
+ const double VoxelSize = InSDFVolume->transform().voxelSize()[0];
+
+ // check that the offset is contained in the narrow band of 2 voxels on each side.
+ checkSlow(2. * VoxelSize > WSOffset && 2. * VoxelSize > -WSOffset);
+
+ const double IsoValue = WSOffset;
+
+ FMixedPolyMesh MixedPolyMesh;
+ openvdb::tools::volumeToMesh(*InSDFVolume, MixedPolyMesh.Points, MixedPolyMesh.Triangles, MixedPolyMesh.Quads, IsoValue, 0.001);
+
+ // convert the mesh to FRawMesh
+ FRawMesh RawMesh;
+ ProxyLOD::MixedPolyMeshToRawMesh(MixedPolyMesh, RawMesh);
+
+ // Create a new empty grid with the same transform and metadata
+ openvdb::FloatGrid::Ptr OutSDFVolume = openvdb::FloatGrid::create(*InSDFVolume);
+ OutSDFVolume->setTransform(openvdb::math::Transform::createLinearTransform(ResultVolexSize));
+
+ // Wrap so we can re-voxelize with bandwidth 2
+ FRawMeshAdapter MeshAdapter(RawMesh, OutSDFVolume->transform());
+
+ // Re-voxelize
+ ProxyLOD::MeshArrayToSDFVolume(MeshAdapter, OutSDFVolume);
+
+ return OutSDFVolume;
+}
+
+
+void ProxyLOD::CloseGaps(openvdb::FloatGrid::Ptr InOutSDFVolume, const double GapRadius, const int32 MaxDilations)
+{
+ // Implimentaiton notes:
+ // This functions by first inflating (dilate) the geometry SDF (moving the surface outward along the normal) an amount
+ // GapRadius. Doing this may bring surfaces into contact, thus closing gaps.
+ // Next the geometry SDF with merged gaps is deflated (erode) to a size that should be slightly smaller than the original geometry.
+ // Lastly a union between the deflated, gap-merged geometry and a copy of the original SDF is formed.
+ // NB: this relies on the fact that grid-based discretization of the SDF at each step of dilation and erosion also smooths
+ // the SDF (dilation isn't exactly reversed by erosion).
+
+
+ // Early out for invalid input.
+
+ if (!InOutSDFVolume)
+ {
+ return;
+ }
+
+ // The voxel size for this grid
+
+ const double InputVoxelSize = InOutSDFVolume->transform().voxelSize()[0];
+
+ // If the gap radius is too small, this won't have an effect.
+
+ if (GapRadius < InputVoxelSize)
+ {
+ return;
+ }
+
+ const double MaxOffsetInVoxels = 1.5;
+
+ // Step configuration using InputVoxelSize
+
+ const double DefaultStepSize = MaxOffsetInVoxels * InputVoxelSize;
+ const int32 DefaultStepNum = FMath::FloorToInt(float( GapRadius / (MaxOffsetInVoxels * InputVoxelSize)));
+ const double DefaultRemainder = GapRadius - DefaultStepNum * DefaultStepSize;
+
+ // Alternate step configuration, deduce working voxel size from MaxIterations
+
+ const double AltStepSize = (GapRadius - InputVoxelSize) / MaxDilations;
+ const int32 AltStepNum = MaxDilations;
+ const double AltRemainder = InputVoxelSize;
+
+ const bool bUseDefaultValues = !(MaxDilations < DefaultStepNum);
+
+ // Choose the correct values to use. Either dilate and erode with the default voxelsize, or using a bigger voxel size.
+
+ double WorkingStepSize;
+ double WorkingRemainder;
+ double WorkingVoxelSize;
+ int32 StepNum;
+ if (bUseDefaultValues)
+ {
+ WorkingStepSize = DefaultStepSize;
+ WorkingRemainder = DefaultRemainder;
+ WorkingVoxelSize = InputVoxelSize;
+ StepNum = DefaultStepNum;
+ }
+ else
+ {
+ WorkingStepSize = AltStepSize;
+ WorkingRemainder = AltRemainder;
+ WorkingVoxelSize = AltStepSize / MaxOffsetInVoxels;
+ StepNum = AltStepNum;
+ }
+
+ openvdb::FloatGrid::Ptr TmpGrid = InOutSDFVolume;
+
+ const bool bRequireRemainder = (!bUseDefaultValues || WorkingRemainder > 0.1 * InputVoxelSize);
+
+ // -- Dilate
+
+ if (bRequireRemainder)
+ {
+ // Note: from inputVoxelSize to WorkingVoxelSize
+ TmpGrid = OffsetSDF(TmpGrid, WorkingRemainder, WorkingVoxelSize);
+ }
+
+ for (int32 step = 0; step < StepNum; ++step)
+ {
+ TmpGrid = OffsetSDF(TmpGrid, WorkingStepSize, WorkingVoxelSize);
+ }
+
+ // -- Erode
+
+ for (int32 step = 0; step < StepNum; ++step)
+ {
+ TmpGrid = OffsetSDF(TmpGrid, -WorkingStepSize, WorkingVoxelSize);
+ }
+
+ if (bRequireRemainder)
+ {
+ // Note: from WorkingVoxelSize to InputVoxelSize
+ TmpGrid = OffsetSDF(TmpGrid, -WorkingRemainder, InputVoxelSize);
+ }
+
+ // Additional Erode to shrink a little more so this hole-filled surface is slightly offset from the higher-quality
+ // original surface
+
+ TmpGrid = OffsetSDF(TmpGrid, -.5 * InputVoxelSize, InputVoxelSize);
+
+ // Union with the higher quality source (this will add the hole plugs..)
+
+ openvdb::tools::csgUnion(*InOutSDFVolume, *TmpGrid);
+
+ // reduce memory footprint, increase sparseness
+
+ const float HalfBandWidth = 2.f;
+ openvdb::tools::pruneLevelSet(InOutSDFVolume->tree(), HalfBandWidth, -HalfBandWidth);
+
+}
+
+void ProxyLOD::RemoveClipped(openvdb::FloatGrid::Ptr InOutSDFVolume, openvdb::FloatGrid::Ptr ClippingVolume)
+{
+
+ // do a difference that deletes the clippling volume from the geometry.
+
+ openvdb::tools::csgDifference(*InOutSDFVolume, *ClippingVolume, true);
+
+ // reduce memory footprint, increase sparseness
+
+ const float HalfBandWidth = 2.f;
+ openvdb::tools::pruneLevelSet(InOutSDFVolume->tree(), HalfBandWidth, -HalfBandWidth);
+}
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.h b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.h
index 55a0623d520b..ec702ec187f8 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.h
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshSDFConversions.h
@@ -32,6 +32,10 @@ namespace ProxyLOD
openvdb::FloatGrid::Ptr& OutSDFGrid,
openvdb::Int32Grid* OutPolyIndexGrid = nullptr);
+ bool MeshArrayToSDFVolume( const FRawMeshAdapter& InMeshAdapter,
+ openvdb::FloatGrid::Ptr& OutSDFGrid,
+ openvdb::Int32Grid* OutPolyIndexGrid = nullptr);
+
/**
* Extract the isosurface (=IsoValue) of the given SDF volume, in the form of triangle mesh.
*
@@ -66,6 +70,38 @@ namespace ProxyLOD
const double IsoValue,
const double Adaptivity,
TAOSMesh& OutMesh);
+
+ /**
+ * Updates the InOutSDFVollume to potentially close small holes and gaps in the iso-surface.
+ *
+ * This is particularly useful when processing distant buildings (where the doors
+ * and windows may only be a few voxels in size). In this case, closing the openings
+ * may result in a water-tight mesh and thus remove interior geometry.
+ *
+ * NB: In addition to closing holes, this may merge nearby separate objects.
+ *
+ * @param InOutSDFVolume Signed distance field that will be altered
+ * @param GapRadius 1/2 the length scale of the gap or hole size.
+ * @param MaxDilations The max allowed number of dilation/erosion pairs,
+ *
+ * NB: If the GapRadius is large compared with the voxelsize of the input volume,
+ * the dilations and erosions will be done with a larger voxelsize (as determined
+ * by MaxDilations).
+ *
+ */
+ void CloseGaps(openvdb::FloatGrid::Ptr InOutSDFVolume, const double GapRadius, const int32 MaxDilations);
+
+ /**
+ * Update the InOutSDFVolume by doing a CSG difference with the Clipping volume.
+ *
+ * NB: In addition to altering the InOutSDFVolume, this may destroy the clipping volume
+ *
+ * @param InOutSDFVolume Signed distance field representing the interesting geometry.
+ * @param ClippingVolume Signed distance field representing the region to be subtracted from the interesting geometry.
+ *
+ */
+ void RemoveClipped(openvdb::FloatGrid::Ptr InOutSDFVolume, openvdb::FloatGrid::Ptr ClippingVolume);
+
}
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshTypes.cpp b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshTypes.cpp
index cf76bbc952f1..0db40183defd 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshTypes.cpp
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshTypes.cpp
@@ -37,6 +37,33 @@ void FRawMeshAdapter::getIndexSpacePoint(size_t FaceNumber, size_t CornerNumber,
// --- FRawMeshArrayAdapter ----
+
+FRawMeshArrayAdapter::FRawMeshArrayAdapter(const TArray& InMergeDataPtrArray)
+{
+ // Make a default transform.
+ Transform = openvdb::math::Transform::createLinearTransform(1.);
+
+ PointCount = 0;
+ PolyCount = 0;
+
+ PolyOffsetArray.push_back(PolyCount);
+ for (int32 MeshIdx = 0, MeshCount = InMergeDataPtrArray.Num(); MeshIdx < MeshCount; ++MeshIdx)
+ {
+ const FMeshMergeData* MergeData = InMergeDataPtrArray[MeshIdx];
+ const FRawMesh* RawMesh = MergeData->RawMesh;
+ PointCount += size_t(RawMesh->VertexPositions.Num());
+ PolyCount += size_t(RawMesh->WedgeIndices.Num() / 3);
+
+ PolyOffsetArray.push_back(PolyCount);
+ RawMeshArray.push_back(RawMesh);
+
+ MergeDataArray.push_back(MergeData);
+ }
+
+ // Compute the bbox
+ ComputeAABB(this->BBox);
+}
+
FRawMeshArrayAdapter::FRawMeshArrayAdapter(const TArray& InMergeDataArray)
{
// Make a default transform.
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshTypes.h b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshTypes.h
index 40905456a2bf..dbea3dab5f5f 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshTypes.h
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshTypes.h
@@ -48,7 +48,7 @@
*/
/**
-* Utility to resize an array.
+* Utility to resize an array with uninitialized data.
* NB: this destroys any content.
*/
template
@@ -58,7 +58,27 @@ void ResizeArray(TArray& Array, int32 Size)
Array.AddUninitialized(Size);
}
+/**
+* Utility to resize an array with constructor initialized data.
+* NB: this destroys any content.
+*/
+template
+void ResizeInializedArray(TArray& Array, int32 Size)
+{
+ if (Size == 0)
+ {
+ TArray EmptyVector;
+ Swap(EmptyVector, Array);
+ }
+ else
+ {
+ TArray Tmp;
+ Tmp.InsertDefaulted(0, Size);
+
+ Swap(Array, Tmp);
+ }
+}
/**
* Mesh type that holds minimal required data for openvdb iso-surface extraction
* interface.
@@ -86,6 +106,10 @@ struct FVertexDataMesh
TArray Normal;
TArray Tangent;
TArray BiTangent;
+
+ // Optional. Used for ray shooting when transfering materials.
+ TArray TransferNormal;
+
// stores information about the tangentspace
// 1 = right handed. -1 left handed
TArray TangentHanded;
@@ -186,6 +210,13 @@ public:
// Return position pos in local grid index space for polygon n and vertex v
void getIndexSpacePoint(size_t FaceNumber, size_t CornerNumber, openvdb::Vec3d& pos) const;
+ /**
+ * The transform used to map between the physical space of the mesh and the voxel space.
+ */
+ const openvdb::math::Transform& GetTransform() const
+ {
+ return *Transform;
+ }
private:
@@ -214,6 +245,8 @@ public:
FRawMeshArrayAdapter(const TArray& InMergeDataArray, const openvdb::math::Transform::Ptr InTransform);
+ FRawMeshArrayAdapter(const TArray& InMergeDataPtrArray);
+
FRawMeshArrayAdapter(const TArray& InMergeDataArray);
// copy constructor
diff --git a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshUtilities.cpp b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshUtilities.cpp
index 281e05d17482..f685b86c7ab2 100644
--- a/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshUtilities.cpp
+++ b/Engine/Plugins/Experimental/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshUtilities.cpp
@@ -13,6 +13,7 @@
#include
#include
+#include