Skip to content

Commit

Permalink
Fixed: Исправлено удаление Updatable
Browse files Browse the repository at this point in the history
  • Loading branch information
Reider745 committed Jan 10, 2025
1 parent b610a9a commit 5fe0bb5
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 177 deletions.
12 changes: 0 additions & 12 deletions src/main/java/com/zhekasmirnov/innercore/api/NativeCallback.java
Original file line number Diff line number Diff line change
Expand Up @@ -316,14 +316,6 @@ public static void onGameStopped(boolean isServer) {
new TPSMeter("mod-thread", 20, 2000);
}

private static void setupWorld() {
int updatableMode = (boolean) InnerCoreConfig.get("performance.time_based_limit") ? Updatable.MODE_TIME_BASED
: Updatable.MODE_COUNT_BASED;
Updatable.setPreferences(updatableMode,
updatableMode == Updatable.MODE_COUNT_BASED ? InnerCoreConfig.getInt("performance.max_update_count")
: InnerCoreConfig.getInt("performance.max_update_time"));
}

public static boolean isServerTickDisabledDueToError() {
return isServerTickDisabledDueToError;
}
Expand All @@ -350,9 +342,6 @@ public static void onTick() {

// run post loaded callback and actions
onLevelPostLoaded(true);

// final setup
setupWorld();
}

// call mod tick
Expand All @@ -370,7 +359,6 @@ public static void onTick() {
}
Updatable.getForServer().onTick();
executor.blockUntilExecuted();
Updatable.getForServer().onPostTick();
ConnectedClientList.onTick();

// run ecs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ private void callTick(Tick tick) {
}
Updatable.getForServer().onTick();
executor.blockUntilExecuted();
Updatable.getForServer().onPostTick();
}

public static class Tick {
Expand Down
216 changes: 52 additions & 164 deletions src/main/java/com/zhekasmirnov/innercore/api/runtime/Updatable.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,23 @@
import org.mozilla.javascript.*;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
* Created by zheka on 10.08.2017.
*/

public class Updatable {
private static final Object[] EMPTY_ARGS = new Object[]{};

private final List<ScriptableObject> updatableObjects = new ArrayList<>();
private final List<ScriptableObject> disabledDueToError = new ArrayList<>();
private final boolean isMultithreadingAllowed;

private Updatable(boolean isMultithreadingAllowed) {
this.isMultithreadingAllowed = isMultithreadingAllowed;
}
private Context currentContext;

public void cleanUp() {
updatableObjects.clear();
disabledDueToError.clear();
postedRemovedUpdatables.clear();
currentArrayPosition = 0;
currentContext = null;
}

Expand All @@ -42,43 +39,14 @@ public void addUpdatable(ScriptableObject obj) {
if (_update instanceof Function) {
updatableObjects.add(obj);
} else {
throw new IllegalArgumentException("cannot add updatable object: <obj>.update must be a function, not "
+ (_update != null ? _update.getClass() : null) + " " + _update);
}
}

public static void cleanUpAll() {
getForServer().cleanUp();
getForClient().cleanUp();
}

public static final int MODE_COUNT_BASED = 0;
public static final int MODE_TIME_BASED = 1;

private static int currentMode = 0;
private static int maxUpdateCallsPerTick = 128;
private static int maxUpdateTimePerTick = 50;

public static void setPreferences(int mode, int modeValue) {
switch (mode) {
case MODE_COUNT_BASED:
maxUpdateCallsPerTick = modeValue;
ICLog.d("THREADING", "updatable engine uses count-based mode, maxCount=" + modeValue);
break;
case MODE_TIME_BASED:
maxUpdateTimePerTick = modeValue;
ICLog.d("THREADING", "updatable engine uses time-based mode, maxTime=" + modeValue);
break;
default:
throw new IllegalArgumentException("invalid updatable engine mode: " + mode);
throw new IllegalArgumentException("cannot add updatable object: <obj>.update must be a function, not " + (_update != null ? _update.getClass() : null) + " " + _update);
}

currentMode = mode;
}

private static boolean shouldBeRemoved(Scriptable obj) {
Object _remove = obj.get("remove", obj);
return (_remove instanceof Boolean && (boolean) _remove);
public static void reportError(Throwable err, String updatableStr) {
Logger.error("UPDATABLE ERROR", new RuntimeException("Updatable " + updatableStr
+ " was disabled due to error, corresponding object will be disabled. To re-enable it re-enter the world.",
err));
}

private static String updatableToString(Context ctx, Scriptable obj) {
Expand All @@ -87,142 +55,60 @@ private static String updatableToString(Context ctx, Scriptable obj) {
try {
Function to_string = (Function) _to_string;
return "" + to_string.call(ctx, to_string.getParentScope(), obj, EMPTY_ARGS);
} catch (Throwable ignore) {
}
} catch (Throwable ignore) { }
}
return "" + obj;
}

public static void reportError(Throwable err, String updatableStr) {
Logger.error("UPDATABLE ERROR", new RuntimeException("Updatable " + updatableStr
+ " was disabled due to error, corresponding object will be disabled. To re-enable it re-enter the world.",
err));
}

private static final Object[] EMPTY_ARGS = new Object[] {};
public void onTick() {
if (currentContext == null) {
currentContext = Compiler.assureContextForCurrentThread();
}

private Context currentContext = null;
final Iterator<ScriptableObject> iterator = updatableObjects.iterator();

private void executeUpdateWithContext(Context ctx, ScriptableObject obj) {
if(shouldBeRemoved(obj)){
postedRemovedUpdatables.add(obj);
return;
}
while (iterator.hasNext()) {
final ScriptableObject updatable = iterator.next();

Object _update = obj.get("update", obj);
try {
Function update = (Function) _update;
update.call(ctx, update.getParentScope(), obj, EMPTY_ARGS);
} catch (Throwable err) {
disabledDueToError.add(obj);
postedRemovedUpdatables.add(obj);
Object _handle_error = obj.get("_handle_error", obj);
if (_handle_error instanceof Function) {
try {
Function handle_error = (Function) _handle_error;
handle_error.call(ctx, handle_error.getParentScope(), obj, new Object[] { err });
} catch (Throwable err2) {
Logger.error("Error occurred in error handler for " + updatableToString(ctx, obj) + " hash="
+ obj.hashCode(), err2);
}
} else {
reportError(err, updatableToString(ctx, obj));
if(ScriptableObjectHelper.getBooleanProperty(updatable, "noupdate", false)) {
continue;
}
return;
}
}

private boolean executeUpdate(ScriptableObject obj) {
if (ScriptableObjectHelper.getBooleanProperty(obj, "noupdate", false)) {
return false;
}

TickExecutor executor = TickExecutor.getInstance();
if (isMultithreadingAllowed && executor.isAvailable()) {
TickExecutor.getInstance().execute(new Runnable() {
@Override
public void run() {
synchronized (obj) {
executeUpdateWithContext(Compiler.assureContextForCurrentThread(), obj);
try {
((Function) updatable.get("update")).call(currentContext, updatable.getParentScope(), updatable, EMPTY_ARGS);
} catch (Throwable e) {
iterator.remove();
disabledDueToError.add(updatable);

final Object _handle_error = updatable.get("_handle_error");
if(_handle_error instanceof Function) {
try {
Function handle_error = (Function) _handle_error;
handle_error.call(currentContext, handle_error.getParentScope(), updatable, new Object[]{e});
} catch (Throwable err2) {
Logger.error("Error occurred in error handler for " + updatableToString(currentContext, updatable) + " hash="
+ updatable.hashCode(), err2);
}
} else {
reportError(e, updatableToString(currentContext, updatable));
}
});
} else {
executeUpdateWithContext(currentContext, obj);
}

return true;
}

private int currentArrayPosition = 0;
private final ArrayList<ScriptableObject> postedRemovedUpdatables = new ArrayList<>();

private void removePosted() {
for (ScriptableObject updatable : postedRemovedUpdatables) {
updatableObjects.remove(updatable);
}
postedRemovedUpdatables.clear();
}

private boolean executeCurrentToNext() {
if (updatableObjects.size() == 0) {
return true;
}
currentArrayPosition = currentArrayPosition % updatableObjects.size();
boolean executed = executeUpdate(updatableObjects.get(currentArrayPosition));
currentArrayPosition++;
return executed;
}

private void onCountBasedTick() {
int callCount = maxUpdateCallsPerTick;

int calls = 0;
for (int i = 0; i < callCount && i < updatableObjects.size();) {
if (calls++ >= updatableObjects.size()) {
break;
continue;
}
if (executeCurrentToNext()) {
i++;
}
}
}

private void onTimeBasedTick() {
int callCount = updatableObjects.size();
long timeStart = System.currentTimeMillis();

for (int i = 0; i < callCount; i++) {
executeCurrentToNext();
long timeCur = System.currentTimeMillis();
if (timeCur - timeStart > maxUpdateTimePerTick) {
break;
if(ScriptableObjectHelper.getBooleanProperty(updatable, "remove", false)) {
iterator.remove();
}
}
}

public void onTick() {
if (currentContext == null) {
currentContext = Compiler.assureContextForCurrentThread();
}
if (currentMode == MODE_COUNT_BASED || isMultithreadingAllowed && TickExecutor.getInstance().isAvailable()) {
onCountBasedTick();
} else if (currentMode == MODE_TIME_BASED) {
onTimeBasedTick();
}
}

public void onPostTick() {
removePosted();
}
// for backward compatibility
@Deprecated
public static void setPreferences(int mode, int modeValue) {}

public void onTickSingleThreaded() {
onTick();
onPostTick();
}

private static final Updatable serverInstance = new Updatable(true);
private static final Updatable clientInstance = new Updatable(false);
private static final Updatable serverInstance = new Updatable();
private static final Updatable clientInstance = new Updatable();

public static Updatable getForServer() {
return serverInstance;
Expand All @@ -232,9 +118,12 @@ public static Updatable getForClient() {
return clientInstance;
}

static {
setPreferences(MODE_COUNT_BASED, 256);
public static void cleanUpAll() {
getForServer().cleanUp();
getForClient().cleanUp();
}

static {
WorldDataScopeRegistry.getInstance().addScope("_updatables", new ScriptableSaverScope() {
@Override
public ScriptableObject save() {
Expand All @@ -245,7 +134,7 @@ public ScriptableObject save() {
}
}
for (ScriptableObject updatable : getForServer().disabledDueToError) {
if (ObjectSaverRegistry.getSaverFor(updatable) != null && !shouldBeRemoved(updatable)) {
if (ObjectSaverRegistry.getSaverFor(updatable) != null && !ScriptableObjectHelper.getBooleanProperty(updatable, "remove", false)) {
updatableObjectsToSave.add(updatable);
}
}
Expand All @@ -266,11 +155,10 @@ public void read(Object scope) {
continue;
}
}
ICLog.i("UPDATABLE",
"loaded updatable data is not a scriptable object or it does not have update function, loading failed. obj="
+ possibleUpdatable);
ICLog.i("UPDATABLE", "loaded updatable data is not a scriptable object or it does not have update function, loading failed. obj=" + possibleUpdatable);
}
} else {
}
else {
ICLog.i("UPDATABLE", "assertion failed: updatable scope is not an array, loading failed");
}

Expand Down

0 comments on commit 5fe0bb5

Please sign in to comment.