mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-09-21 06:13:49 -04:00
Finished rewrite of sampling
This commit is contained in:
+31
-108
@@ -26,146 +26,69 @@
|
||||
***********************************************************************************/
|
||||
package com.projectswg.holocore.resources.gameplay.crafting.survey;
|
||||
|
||||
import com.projectswg.common.data.encodables.oob.ProsePackage;
|
||||
import com.projectswg.common.data.encodables.oob.StringId;
|
||||
import com.projectswg.common.data.encodables.oob.waypoint.WaypointColor;
|
||||
import com.projectswg.common.data.encodables.tangible.Posture;
|
||||
import com.projectswg.common.data.location.Location;
|
||||
import com.projectswg.common.network.packets.swg.zone.PlayClientEffectObjectMessage;
|
||||
import com.projectswg.common.network.packets.swg.zone.PlayMusicMessage;
|
||||
import com.projectswg.common.network.packets.swg.zone.chat.ChatSystemMessage;
|
||||
import com.projectswg.common.network.packets.swg.zone.chat.ChatSystemMessage.SystemChatType;
|
||||
import com.projectswg.holocore.intents.support.global.network.CloseConnectionIntent;
|
||||
import com.projectswg.holocore.intents.support.objects.swg.DestroyObjectIntent;
|
||||
import com.projectswg.holocore.intents.support.objects.swg.ObjectCreatedIntent;
|
||||
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.GalacticResource;
|
||||
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.GalacticResourceSpawn;
|
||||
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.GalacticResourceStats;
|
||||
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.RawResourceType;
|
||||
import com.projectswg.holocore.resources.gameplay.crafting.resource.galactic.storage.GalacticResourceContainer;
|
||||
import com.projectswg.holocore.resources.gameplay.crafting.resource.raw.RawResource;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.StandardLog;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.CollectionLoader.CollectionSlotInfo;
|
||||
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader;
|
||||
import com.projectswg.holocore.resources.support.global.network.DisconnectReason;
|
||||
import com.projectswg.holocore.resources.support.global.player.Player;
|
||||
import com.projectswg.holocore.resources.support.global.zone.sui.SuiButtons;
|
||||
import com.projectswg.holocore.resources.support.global.zone.sui.SuiListBox;
|
||||
import com.projectswg.holocore.resources.support.global.zone.sui.SuiMessageBox;
|
||||
import com.projectswg.holocore.resources.support.global.zone.sui.SuiWindow;
|
||||
import com.projectswg.holocore.resources.support.objects.ObjectCreator;
|
||||
import com.projectswg.holocore.resources.support.objects.permissions.ContainerResult;
|
||||
import com.projectswg.holocore.resources.support.objects.permissions.ReadWritePermissions;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.ServerAttribute;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.resource.ResourceContainerObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.tangible.TangibleObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.waypoint.WaypointObject;
|
||||
import me.joshlarson.jlcommon.concurrency.ScheduledThreadPool;
|
||||
import me.joshlarson.jlcommon.control.IntentChain;
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SampleHandler {
|
||||
|
||||
private final AtomicReference<Location> sampleLocation;
|
||||
private final AtomicReference<ScheduledFuture<?>> sampleLoop;
|
||||
private final CreatureObject creature;
|
||||
private final TangibleObject surveyTool;
|
||||
private final AtomicBoolean running;
|
||||
private final SampleLoopSession session;
|
||||
private final ScheduledThreadPool executor;
|
||||
|
||||
private volatile @Nullable SampleLoopSession sampleSession;
|
||||
|
||||
public SampleHandler(CreatureObject creature, TangibleObject surveyTool, ScheduledThreadPool executor) {
|
||||
this.sampleLocation = new AtomicReference<>(null);
|
||||
this.sampleLoop = new AtomicReference<>(null);
|
||||
this.session = new AtomicReference<>(null);
|
||||
this.creature = creature;
|
||||
this.surveyTool = surveyTool;
|
||||
this.running = new AtomicBoolean(false);
|
||||
this.executor = executor;
|
||||
|
||||
this.sampleSession = null;
|
||||
}
|
||||
|
||||
public void startSession() {
|
||||
public synchronized void startSession() {
|
||||
|
||||
}
|
||||
|
||||
public void stopSession() {
|
||||
stopSampleLoop();
|
||||
public synchronized void stopSession() {
|
||||
SampleLoopSession session = this.sampleSession;
|
||||
this.sampleSession = null;
|
||||
if (session != null)
|
||||
session.stopSession();
|
||||
}
|
||||
|
||||
public void startSampleLoop(GalacticResource resource) {
|
||||
Location location = creature.getWorldLocation();
|
||||
double concentration = getConcentration(resource, location);
|
||||
public synchronized void startSampleLoop(GalacticResource resource) {
|
||||
Location sampleLocation = creature.getWorldLocation();
|
||||
|
||||
if (!isAllowedToSample(resource, concentration))
|
||||
return;
|
||||
|
||||
if (!running.getAndSet(true)) {
|
||||
ScheduledFuture<?> prevLoop = sampleLoop.getAndSet(executor.executeWithFixedRate(5000, 5000, () -> sample(resource, location)));
|
||||
stopSampleLoop(prevLoop);
|
||||
sampleLocation.set(location);
|
||||
creature.setPosture(Posture.CROUCHED);
|
||||
creature.setMovementPercent(0);
|
||||
creature.setTurnScale(0);
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, new ProsePackage(new StringId("@survey:start_sampling"), "TO", resource.getName())));
|
||||
Log.d("%s started a sample session with %s and concentration %.1f", creature.getObjectName(), resource.getName(), concentration);
|
||||
SampleLoopSession prevSession = this.sampleSession;
|
||||
if (prevSession != null && prevSession.isMatching(creature, surveyTool, resource, sampleLocation)) {
|
||||
if (!prevSession.isSampling())
|
||||
prevSession.startSession(executor);
|
||||
} else {
|
||||
SampleLoopSession nextSession = new SampleLoopSession(creature, surveyTool, resource, sampleLocation);
|
||||
if (prevSession != null)
|
||||
prevSession.stopSession();
|
||||
nextSession.startSession(executor);
|
||||
this.sampleSession = nextSession;
|
||||
}
|
||||
}
|
||||
|
||||
public void onPlayerMoved() {
|
||||
Location oldLocation = sampleLocation.get();
|
||||
Location newLocation = creature.getWorldLocation();
|
||||
|
||||
if (oldLocation == null)
|
||||
return;
|
||||
if (oldLocation.distanceTo(newLocation) >= 0.5 || oldLocation.getTerrain() != newLocation.getTerrain())
|
||||
stopSampleLoop();
|
||||
public synchronized void onPlayerMoved() {
|
||||
SampleLoopSession session = this.sampleSession;
|
||||
if (session != null)
|
||||
session.onPlayerMoved();
|
||||
}
|
||||
|
||||
public void stopSampleLoop() {
|
||||
if (!running.getAndSet(false))
|
||||
return;
|
||||
stopSampleLoop(sampleLoop.getAndSet(null));
|
||||
public synchronized void stopSampleLoop() {
|
||||
stopSession();
|
||||
}
|
||||
|
||||
public boolean isSampling() {
|
||||
ScheduledFuture<?> loop = this.sampleLoop.get();
|
||||
return loop != null && !loop.isDone();
|
||||
}
|
||||
|
||||
private void stopSampleLoop(ScheduledFuture<?> loop) {
|
||||
if (loop != null && loop.cancel(false)) {
|
||||
creature.setPosture(Posture.UPRIGHT);
|
||||
creature.setMovementPercent(1);
|
||||
creature.setTurnScale(1);
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:sample_cancel"));
|
||||
SuiWindow window = this.sampleWindow.get();
|
||||
if (window != null)
|
||||
window.close(creature.getOwner());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAllowedToSample(GalacticResource resource, double concentration) {
|
||||
if (creature.getSkillModValue("surveying") < 20) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "You aren't allowed to sample without a surveying skillmod"));
|
||||
return false;
|
||||
}
|
||||
if (creature.isInCombat()) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:sample_cancel_attack"));
|
||||
return false;
|
||||
}
|
||||
if (concentration <= 0.3) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, new ProsePackage(new StringId("@survey:density_below_threshold"), "TO", resource.getName())));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
SampleLoopSession session = this.sampleSession;
|
||||
return session != null && session.isSampling();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+102
-32
@@ -30,6 +30,7 @@ package com.projectswg.holocore.resources.gameplay.crafting.survey;
|
||||
import com.projectswg.common.data.encodables.oob.ProsePackage;
|
||||
import com.projectswg.common.data.encodables.oob.StringId;
|
||||
import com.projectswg.common.data.encodables.oob.waypoint.WaypointColor;
|
||||
import com.projectswg.common.data.encodables.tangible.Posture;
|
||||
import com.projectswg.common.data.location.Location;
|
||||
import com.projectswg.common.network.packets.swg.zone.PlayClientEffectObjectMessage;
|
||||
import com.projectswg.common.network.packets.swg.zone.PlayMusicMessage;
|
||||
@@ -58,12 +59,14 @@ import com.projectswg.holocore.resources.support.objects.permissions.ContainerRe
|
||||
import com.projectswg.holocore.resources.support.objects.permissions.ReadWritePermissions;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.ServerAttribute;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureState;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.resource.ResourceContainerObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.tangible.TangibleObject;
|
||||
import com.projectswg.holocore.resources.support.objects.swg.waypoint.WaypointObject;
|
||||
import me.joshlarson.jlcommon.concurrency.ScheduledThreadPool;
|
||||
import me.joshlarson.jlcommon.control.IntentChain;
|
||||
import me.joshlarson.jlcommon.log.Log;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
@@ -72,65 +75,96 @@ import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class SampleLoopSession {
|
||||
|
||||
private final CreatureObject creature;
|
||||
private final TangibleObject surveyTool;
|
||||
private final GalacticResource resource;
|
||||
private final @NotNull CreatureObject creature;
|
||||
private final @NotNull TangibleObject surveyTool;
|
||||
private final @NotNull GalacticResource resource;
|
||||
private final @NotNull Location sampleLocation;
|
||||
|
||||
private SuiWindow sampleWindow;
|
||||
private Location sampleLocation;
|
||||
private ScheduledFuture<?> loopFuture;
|
||||
private boolean paused;
|
||||
private int sampleMultiplier;
|
||||
|
||||
public SampleLoopSession(CreatureObject creature, TangibleObject surveyTool, GalacticResource resource) {
|
||||
public SampleLoopSession(@NotNull CreatureObject creature, @NotNull TangibleObject surveyTool, @NotNull GalacticResource resource, @NotNull Location sampleLocation) {
|
||||
this.creature = creature;
|
||||
this.surveyTool = surveyTool;
|
||||
this.resource = resource;
|
||||
this.sampleLocation = sampleLocation;
|
||||
|
||||
this.sampleWindow = null;
|
||||
this.sampleLocation = null;
|
||||
this.loopFuture = null;
|
||||
this.paused = false;
|
||||
this.sampleMultiplier = 1;
|
||||
}
|
||||
|
||||
public synchronized void startSession(ScheduledThreadPool executor, GalacticResource resource, Location sampleLocation) {
|
||||
this.sampleLocation = sampleLocation;
|
||||
public boolean isMatching(CreatureObject creature, TangibleObject surveyTool, GalacticResource resource, Location sampleLocation) {
|
||||
if (this.sampleLocation.distanceTo(sampleLocation) >= 0.5 || this.sampleLocation.getTerrain() != sampleLocation.getTerrain())
|
||||
return false; // Too far away for the same session
|
||||
return this.creature.equals(creature) && this.surveyTool.equals(surveyTool) && this.resource.equals(resource);
|
||||
}
|
||||
|
||||
public synchronized boolean isSampling() {
|
||||
return loopFuture != null && !loopFuture.isDone();
|
||||
}
|
||||
|
||||
public synchronized void onPlayerMoved() {
|
||||
Location oldLocation = sampleLocation;
|
||||
Location newLocation = creature.getWorldLocation();
|
||||
|
||||
if (oldLocation.distanceTo(newLocation) >= 0.5 || oldLocation.getTerrain() != newLocation.getTerrain())
|
||||
stopSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to start the sample loop session with the specified executor. If the loop is unable to start, this function returns false; otherwise this function returns true.
|
||||
* @param executor the executor for the loop to run on
|
||||
* @return TRUE if the sample loop has begin, FALSE otherwise
|
||||
*/
|
||||
public synchronized boolean startSession(ScheduledThreadPool executor) {
|
||||
if (loopFuture != null) {
|
||||
loopFuture.cancel(false);
|
||||
}
|
||||
double concentration = getConcentration();
|
||||
if (!isAllowedToSample(concentration))
|
||||
return false;
|
||||
|
||||
loopFuture = executor.executeWithFixedRate(5000, 5000, this::sample);
|
||||
creature.setPosture(Posture.CROUCHED);
|
||||
creature.setMovementPercent(0);
|
||||
creature.setTurnScale(0);
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, new ProsePackage(new StringId("@survey:start_sampling"), "TO", resource.getName())));
|
||||
StandardLog.onPlayerTrace(this, creature, "started a sample session with %s and concentration %.1f", resource.getName(), concentration);
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized void stopSession() {
|
||||
if (loopFuture != null)
|
||||
loopFuture.cancel(false);
|
||||
else
|
||||
return;
|
||||
loopFuture = null;
|
||||
if (sampleWindow != null) {
|
||||
Player owner = creature.getOwner();
|
||||
if (owner != null)
|
||||
sampleWindow.close(owner);
|
||||
}
|
||||
sampleWindow = null;
|
||||
|
||||
creature.setPosture(Posture.UPRIGHT);
|
||||
creature.setMovementPercent(1);
|
||||
creature.setTurnScale(1);
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:sample_cancel"));
|
||||
}
|
||||
|
||||
private synchronized void sample() {
|
||||
if (GalacticResourceContainer.getContainer().getTerrainResourceSpawns(resource, creature.getTerrain()).isEmpty()) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:sample_empty"));
|
||||
stopSession();
|
||||
return;
|
||||
}
|
||||
if (!creature.getInventory().getContainedObjects().contains(surveyTool)) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:sample_gone"));
|
||||
stopSession();
|
||||
return;
|
||||
}
|
||||
double concentration = getConcentration();
|
||||
if (concentration <= 0.3) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, new ProsePackage(new StringId("@survey:density_below_threshold"), "TO", resource.getName())));
|
||||
stopSession();
|
||||
return;
|
||||
}
|
||||
if (paused)
|
||||
private void sample() {
|
||||
final double concentration = getConcentration();
|
||||
if (!isAllowedToSample(concentration) || paused)
|
||||
return;
|
||||
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
if (random.nextDouble() > concentration) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, new ProsePackage(new StringId("@survey:sample_failed"), "TO", resource.getName())));
|
||||
sendSampleEffects();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -167,8 +201,7 @@ public class SampleLoopSession {
|
||||
ObjectCreatedIntent.broadcast(resourceObject);
|
||||
break;
|
||||
}
|
||||
creature.sendSelf(new PlayMusicMessage(0, getMusicFile(), 1, false));
|
||||
creature.sendObservers(new PlayClientEffectObjectMessage(getEffectFile(), "", creature.getObjectId(), ""));
|
||||
sendSampleEffects();
|
||||
}
|
||||
|
||||
private void openConcentrationWindow() {
|
||||
@@ -230,9 +263,6 @@ public class SampleLoopSession {
|
||||
}
|
||||
|
||||
private void createHighestConcentrationWaypoint() {
|
||||
if (sampleLocation == null)
|
||||
return;
|
||||
|
||||
double highestX = sampleLocation.getX();
|
||||
double highestZ = sampleLocation.getZ();
|
||||
double highest = 0;
|
||||
@@ -258,6 +288,41 @@ public class SampleLoopSession {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:node_waypoint"));
|
||||
}
|
||||
|
||||
private boolean isAllowedToSample(double concentration) {
|
||||
if (GalacticResourceContainer.getContainer().getTerrainResourceSpawns(resource, creature.getTerrain()).isEmpty()) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:sample_empty"));
|
||||
stopSession();
|
||||
return false;
|
||||
}
|
||||
if (!creature.getInventory().getContainedObjects().contains(surveyTool)) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:sample_gone"));
|
||||
stopSession();
|
||||
return false;
|
||||
}
|
||||
if (creature.getSkillModValue("surveying") < 20) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "You aren't allowed to sample without a surveying skillmod"));
|
||||
return false;
|
||||
}
|
||||
if (creature.isStatesBitmask(CreatureState.RIDING_MOUNT)) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "You aren't allowed to sample while on a mount"));
|
||||
return false;
|
||||
}
|
||||
if (creature.getParent() != null) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "You aren't allowed to sample while within a building"));
|
||||
return false;
|
||||
}
|
||||
if (creature.isInCombat()) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, "@survey:sample_cancel_attack"));
|
||||
return false;
|
||||
}
|
||||
if (concentration <= 0.3) {
|
||||
creature.sendSelf(new ChatSystemMessage(SystemChatType.PERSONAL, new ProsePackage(new StringId("@survey:density_below_threshold"), "TO", resource.getName())));
|
||||
stopSession();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private double getConcentration() {
|
||||
List<GalacticResourceSpawn> spawns = GalacticResourceContainer.getContainer().getTerrainResourceSpawns(resource, creature.getTerrain());
|
||||
double concentration = 0;
|
||||
@@ -295,10 +360,15 @@ public class SampleLoopSession {
|
||||
transferStat(obj, "res_toughness", stats.getUnitToughness());
|
||||
}
|
||||
|
||||
private static void transferStat(TangibleObject obj, String name, int attr) {
|
||||
private void transferStat(TangibleObject obj, String name, int attr) {
|
||||
obj.addAttribute("@obj_attr_n:" + name, String.valueOf(attr));
|
||||
}
|
||||
|
||||
private void sendSampleEffects() {
|
||||
creature.sendSelf(new PlayMusicMessage(0, getMusicFile(), 1, false));
|
||||
creature.sendObservers(new PlayClientEffectObjectMessage(getEffectFile(), "", creature.getObjectId(), ""));
|
||||
}
|
||||
|
||||
private String getMusicFile() {
|
||||
RawResource rawResource = resource.getRawResource();
|
||||
if (RawResourceType.MINERAL.isResourceType(rawResource))
|
||||
|
||||
Reference in New Issue
Block a user