Make level key requests work kinda
This commit is contained in:
@@ -130,12 +130,6 @@ public class ClientApi
|
||||
|
||||
public boolean rendererDisabledBecauseOfExceptions = false;
|
||||
|
||||
private final ClientPluginChannelApi pluginChannelApi = new ClientPluginChannelApi();
|
||||
|
||||
/** Delay loading the first level to give the server some time to respond with level to actually load */
|
||||
private Timer firstLevelLoadTimer;
|
||||
private static final long FIRST_LEVEL_LOAD_DELAY_IN_MS = 1_000;
|
||||
|
||||
/** Holds any levels that were loaded before the {@link ClientApi#onClientOnlyConnected} was fired. */
|
||||
public final HashSet<IClientLevelWrapper> waitingClientLevels = new HashSet<>();
|
||||
/** Holds any chunks that were found before the client levels are loaded. */
|
||||
@@ -220,22 +214,12 @@ public class ClientApi
|
||||
|
||||
DhClientWorld world = new DhClientWorld();
|
||||
SharedApi.setDhWorld(world);
|
||||
|
||||
this.pluginChannelApi.onJoinServer(world.networkState.getSession());
|
||||
world.networkState.sendConfigMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/** Synchronized to prevent a rare issue where multiple disconnect events are triggered on top of each other. */
|
||||
public synchronized void onClientOnlyDisconnected()
|
||||
{
|
||||
// clear the first time timer
|
||||
if (this.firstLevelLoadTimer != null)
|
||||
{
|
||||
this.firstLevelLoadTimer.cancel();
|
||||
this.firstLevelLoadTimer = null;
|
||||
}
|
||||
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world != null)
|
||||
{
|
||||
@@ -245,8 +229,6 @@ public class ClientApi
|
||||
SharedApi.setDhWorld(null);
|
||||
}
|
||||
|
||||
this.pluginChannelApi.reset();
|
||||
|
||||
// remove any waiting items
|
||||
this.waitingChunkByClientLevelAndPos.clear();
|
||||
}
|
||||
@@ -255,55 +237,6 @@ public class ClientApi
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// level events //
|
||||
//==============//
|
||||
//region level events
|
||||
|
||||
/**
|
||||
* used in conjunction with the server networking to
|
||||
* handle level load requests.
|
||||
*/
|
||||
public boolean canLoadClientLevel(IClientLevelWrapper wrapper)
|
||||
{
|
||||
// wait a moment before loading the level to give the server a chance to handle the client's login request
|
||||
if (MC_CLIENT.clientConnectedToDedicatedServer())
|
||||
{
|
||||
if (this.firstLevelLoadTimer == null)
|
||||
{
|
||||
this.firstLevelLoadTimer = TimerUtil.CreateTimer("FirstLevelLoadTimer");
|
||||
this.firstLevelLoadTimer.schedule(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
public void run() { canLoadClientLevel(wrapper); }
|
||||
}, FIRST_LEVEL_LOAD_DELAY_IN_MS);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.firstLevelLoadTimer.cancel();
|
||||
}
|
||||
|
||||
if (!this.pluginChannelApi.allowLevelLoading(wrapper))
|
||||
{
|
||||
LOGGER.debug("Client levels in this connection are managed by the server, skipping auto-load of: ["+wrapper+"]");
|
||||
AbstractDhWorld world = SharedApi.getAbstractDhWorld();
|
||||
if (world == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Instead of attempting to load themselves, send the config and wait for a server provided level key.
|
||||
((DhClientWorld) world).networkState.sendLevelInitRequest(wrapper.getDimensionName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// level events //
|
||||
//==============//
|
||||
@@ -358,7 +291,8 @@ public class ClientApi
|
||||
{
|
||||
executor.execute(() ->
|
||||
{
|
||||
NetworkSession networkSession = this.pluginChannelApi.networkSession;
|
||||
DhClientWorld world = (DhClientWorld) Objects.requireNonNull(SharedApi.tryGetDhClientWorld());
|
||||
NetworkSession networkSession = world.pluginChannelApi.networkSession;
|
||||
if (networkSession != null)
|
||||
{
|
||||
networkSession.tryHandleMessage(message);
|
||||
|
||||
-2
@@ -69,8 +69,6 @@ public class ServerPlayerState implements Closeable
|
||||
this.networkSession.registerHandler(SessionConfigMessage.class, (sessionConfigMessage) ->
|
||||
{
|
||||
this.sessionConfig.constrainingConfig = sessionConfigMessage.config;
|
||||
|
||||
this.sendLevelKey();
|
||||
this.sendConfigMessage();
|
||||
});
|
||||
|
||||
|
||||
@@ -19,13 +19,16 @@
|
||||
|
||||
package com.seibel.distanthorizons.core.world;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelLoadEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiLevelUnloadEvent;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientPluginChannelApi;
|
||||
import com.seibel.distanthorizons.core.enums.MinecraftTextFormat;
|
||||
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
|
||||
import com.seibel.distanthorizons.core.level.DhClientLevel;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
||||
import com.seibel.distanthorizons.core.multiplayer.client.ClientNetworkState;
|
||||
import com.seibel.distanthorizons.core.util.TimerUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
@@ -36,6 +39,8 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
{
|
||||
@@ -58,6 +63,14 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
|
||||
private final Timer clientTickTimer = TimerUtil.CreateTimer("ClientTickTimer");
|
||||
|
||||
public final ClientPluginChannelApi pluginChannelApi = new ClientPluginChannelApi();
|
||||
private static final long FIRST_LEVEL_LOAD_DELAY_IN_MS = 1_000;
|
||||
/** Delay loading the first level to give the server some time to respond with level to actually load */
|
||||
private long allowLoadingLevelsAfter = 0;
|
||||
private final ConcurrentMap<String, Boolean> levelInitRequestDebounce = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(FIRST_LEVEL_LOAD_DELAY_IN_MS, TimeUnit.MILLISECONDS)
|
||||
.<String, Boolean>build()
|
||||
.asMap();
|
||||
|
||||
|
||||
//==============//
|
||||
@@ -73,6 +86,9 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
|
||||
LOGGER.info("Started DhWorld of type " + this.environment);
|
||||
|
||||
this.pluginChannelApi.onJoinServer(networkState.getSession());
|
||||
this.networkState.sendConfigMessage();
|
||||
|
||||
this.clientTickTimer.scheduleAtFixedRate(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
@@ -119,7 +135,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ClientApi.INSTANCE.canLoadClientLevel(clientLevelWrapper))
|
||||
if (!this.ensureLevelKeyWhenAvailable(clientLevelWrapper))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -148,6 +164,44 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ensureLevelKeyWhenAvailable(@NotNull IClientLevelWrapper clientLevelWrapper)
|
||||
{
|
||||
if (!this.pluginChannelApi.allowLevelLoading(clientLevelWrapper))
|
||||
{
|
||||
LOGGER.debug("Client levels in this connection are managed by the server, skipping auto-load of: ["+clientLevelWrapper+"]");
|
||||
|
||||
// Instead of attempting to load themselves, send the config and wait for a server provided level key
|
||||
// Debounce is to prevent request spam caused by code trying to load the level every frame
|
||||
levelInitRequestDebounce.computeIfAbsent(clientLevelWrapper.getDimensionName(), dimensionName -> {
|
||||
this.networkState.sendLevelInitRequest(dimensionName);
|
||||
return true;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make non-keyed levels wait some delay since first attempt to load anything,
|
||||
// so the server can reply to the level key request
|
||||
if (!(clientLevelWrapper instanceof IServerKeyedClientLevel))
|
||||
{
|
||||
if (this.allowLoadingLevelsAfter == 0)
|
||||
{
|
||||
// Debounce is to prevent request spam caused by code trying to load the level every frame
|
||||
levelInitRequestDebounce.computeIfAbsent(clientLevelWrapper.getDimensionName(), dimensionName -> {
|
||||
this.networkState.sendLevelInitRequest(dimensionName);
|
||||
return true;
|
||||
});
|
||||
this.allowLoadingLevelsAfter = System.currentTimeMillis() + FIRST_LEVEL_LOAD_DELAY_IN_MS;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() < this.allowLoadingLevelsAfter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhClientLevel getLevel(@NotNull ILevelWrapper wrapper)
|
||||
{
|
||||
@@ -202,6 +256,7 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
|
||||
public void close()
|
||||
{
|
||||
this.networkState.close();
|
||||
this.pluginChannelApi.reset();
|
||||
|
||||
ArrayList<CompletableFuture<Void>> closeFutures = new ArrayList<>();
|
||||
for (DhClientLevel dhClientLevel : this.clientLevelByDhId.values())
|
||||
|
||||
Reference in New Issue
Block a user