Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft schematics #1341

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,653 changes: 1,653 additions & 0 deletions serverdata/crafting/schematic_group.sdb

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/***********************************************************************************
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.data.server_info.loader

import com.projectswg.common.data.CRC
import com.projectswg.common.data.encodables.oob.StringId
import com.projectswg.common.data.schematic.DraftSchematic
import com.projectswg.common.data.schematic.DraftSlotDataOption
import com.projectswg.common.data.schematic.IngridientSlot
import com.projectswg.common.data.schematic.IngridientSlot.IngridientType
import com.projectswg.common.data.swgfile.ClientFactory
import com.projectswg.common.data.swgfile.visitors.ObjectData
import com.projectswg.holocore.resources.support.data.server_info.StandardLog
import me.joshlarson.json.JSON
import me.joshlarson.json.JSONObject
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths
import kotlin.text.Charsets.UTF_8

class DraftSchematicLoader : DataLoader() {

private val draftSchematics: MutableMap<String, DraftSchematic> = HashMap()

fun getDraftSchematic(draftSchematicIff: String): DraftSchematic? {
return draftSchematics[draftSchematicIff]
}

override fun load() {
val what = "draft schematics"
val start = StandardLog.onStartLoad(what)

loadAllDraftSchematics()

StandardLog.onEndLoad(draftSchematics.size, what, start)
}

private fun loadAllDraftSchematics() {
val files = findAllDraftSchematicJsonFiles()

for (file in files) {
val jsonFilePath = file.path
val iffDraftSchematicPath = jsonFilePath.replace("\\", "/").replaceFirst("serverdata/", "object/").replace(".json", ".iff")
val fileToJsonString = fileToJsonString(file)
val sharedIffDraftSchematicPath = ClientFactory.formatToSharedFile(iffDraftSchematicPath)
val draftSchematic = jsonToDraftSchematic(fileToJsonString, sharedIffDraftSchematicPath)

draftSchematics[sharedIffDraftSchematicPath] = draftSchematic
}
}

private fun findAllDraftSchematicJsonFiles(): List<File> {
val base = Paths.get("serverdata/draft_schematic")
val pathStream = Files.find(base, 10, { path, _ -> path.toString().endsWith(".json") })

return pathStream.map { it.toFile() }.toList()
}

private fun fileToJsonString(file: File): String {
return file.readText(charset = UTF_8)
}

private fun jsonToDraftSchematic(json: String, iffDraftSchematicPath: String): DraftSchematic {
val draftSchematic = DraftSchematic()
val jsonObject = JSON.readObject(json)

setItemsPerContainer(jsonObject, draftSchematic)
setCraftedSharedTemplate(jsonObject, draftSchematic)
setCombinedCrc(iffDraftSchematicPath, draftSchematic)
setVolume(jsonObject, draftSchematic)
setComplexity(jsonObject, draftSchematic)
setSlots(jsonObject, draftSchematic)

return draftSchematic
}

private fun setSlots(jsonObject: JSONObject, draftSchematic: DraftSchematic) {
if (jsonObject.containsKey("slots")) {
val array = jsonObject.getArray("slots")
for (any in array) {
val slotObject = any as Map<*, *>
val name = stringIdName(slotObject)
val optional = slotObject["optional"] as Boolean
val slot = IngridientSlot(name, optional)
draftSchematic.ingridientSlot.add(slot)

setOptions(slotObject, slot)
}
}
}

private fun setOptions(slotObject: Map<*, *>, slot: IngridientSlot) {
val options = slotObject["options"] as List<Map<*, *>>
for (option in options) {
val ingredientType = ingridientType(option)
setIngredients(option, slot, ingredientType)
}
}

private fun ingridientType(option: Map<*, *>) : IngridientType {
val value = option["ingredientType"] as String

return when (value) {
"IT_none" -> IngridientType.IT_NONE
"IT_resourceType" -> IngridientType.IT_RESOURCE_TYPE
"IT_resourceClass" -> IngridientType.IT_RESOURCE_CLASS
"IT_template" -> IngridientType.IT_TEMPLATE
"IT_templateGeneric" -> IngridientType.IT_TEMPLATE
"IT_schematic" -> IngridientType.IT_SCHEMATIC
else -> throw IllegalArgumentException("Unknown ingredient type: $value. Maybe it just needs to be mapped?")
}
}

private fun setIngredients(option: Map<*, *>, slot: IngridientSlot, ingredientType: IngridientType) {
val ingredients = option["ingredients"] as List<Map<*, *>>

for (ingredient in ingredients) {
val name = stringIdName(ingredient)
val ingredientName = ingredient["ingredient"] as String
val amount = (ingredient["count"] as Long).toInt()
slot.addSlotDataOption(DraftSlotDataOption(name, resolveIngredientName(ingredientName), ingredientType.slotType, amount))
}
}

private fun setComplexity(jsonObject: JSONObject, draftSchematic: DraftSchematic) {
val complexity = jsonObject["complexity"] as Long?
if (complexity != null) {
draftSchematic.complexity = complexity.toInt()
}
}

private fun setVolume(jsonObject: JSONObject, draftSchematic: DraftSchematic) {
val volume = jsonObject["volume"] as Long?
if (volume != null) {
draftSchematic.volume = volume.toInt()
}
}

private fun setItemsPerContainer(jsonObject: JSONObject, draftSchematic: DraftSchematic) {
val itemsPerContainer = jsonObject["itemsPerContainer"] as Long?
if (itemsPerContainer != null) {
draftSchematic.itemsPerContainer = itemsPerContainer.toInt()
draftSchematic.isCanManufacture = itemsPerContainer > 0
}
}

private fun setCraftedSharedTemplate(jsonObject: JSONObject, draftSchematic: DraftSchematic) {
val craftedObjectTemplate = jsonObject["craftedObjectTemplate"] as String?
if (!craftedObjectTemplate.isNullOrEmpty()) {
draftSchematic.craftedSharedTemplate = ClientFactory.formatToSharedFile(craftedObjectTemplate)
}
}

private fun setCombinedCrc(iffDraftSchematicPath: String, draftSchematic: DraftSchematic) {
val serverCrc = getDraftSchematicServerCrc(iffDraftSchematicPath)
val clientCrc = getDraftSchematicClientCrc(iffDraftSchematicPath)
val combinedCrc = combinedCrc(serverCrc = serverCrc, clientCrc = clientCrc)
draftSchematic.combinedCrc = combinedCrc
}

private fun stringIdName(map: Map<*, *>): StringId {
val nameStrings = map["name"] as List<String>
return StringId(nameStrings[0], nameStrings[1])
}

private fun getDraftSchematicServerCrc(schematicInGroupShared: String): Int {
return CRC.getCrc(schematicInGroupShared)
}

private fun getDraftSchematicClientCrc(schematicInGroupShared: String): Int {
val templateWithoutPrefix = schematicInGroupShared.replace("object/draft_schematic/", "")
return CRC.getCrc(templateWithoutPrefix)
}

private fun combinedCrc(serverCrc: Int, clientCrc: Int): Long {
return serverCrc.toLong() shl 32 and -0x100000000L or (clientCrc.toLong() and 0x00000000FFFFFFFFL)
}

private fun resolveIngredientName(ingredientName: String): String {
if (ingredientName.endsWith(".iff")) {
val attributes = ServerData.objectData.getAttributes(ClientFactory.formatToSharedFile(ingredientName))
if (attributes != null) {
val stringId = attributes[ObjectData.ObjectDataAttribute.OBJECT_NAME] as StringId
return stringId.toString()
}
}

return ingredientName
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/***********************************************************************************
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.data.server_info.loader

import com.projectswg.holocore.resources.support.data.server_info.SdbLoader
import java.io.File

class SchematicGroupLoader : DataLoader() {

private val schematicGroupMap = mutableMapOf<String, MutableCollection<String>>()

/**
* Returns a collection of all schematic names in the given group
* Example: getSchematicsInGroup("craftDroidDamageRepairA") returns a collection of ["object/draft_schematic/droid/droid_damage_repair_kit_a.iff"]
*/
fun getSchematicsInGroup(groupId: String): Collection<String> {
return schematicGroupMap.getOrElse(groupId) { emptyList() }
}

override fun load() {
val set = SdbLoader.load(File("serverdata/crafting/schematic_group.sdb"))

set.use {
while (set.next()) {
val groupid = set.getText("groupid")
val schematicname = set.getText("schematicname")

if (groupid != "end") {
ensureSchematicGroupExists(groupid)
appendSchematicToGroup(groupid, schematicname)
}
}
}
}

private fun appendSchematicToGroup(groupid: String, schematicname: String) {
schematicGroupMap[groupid]?.add(schematicname)
}

private fun ensureSchematicGroupExists(groupid: String) {
if (!schematicGroupMap.containsKey(groupid)) {
schematicGroupMap[groupid] = mutableListOf()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ object ServerData {
val defaultChatRooms by SoftDataLoaderDelegate(::DefaultChatRoomLoader)
val planetChatRooms by SoftDataLoaderDelegate(::PlanetChatRoomLoader)
val staticCityPoints by SoftDataLoaderDelegate(::StaticCityPointLoader)
val schematicGroups by SoftDataLoaderDelegate(::SchematicGroupLoader)
val draftSchematics by SoftDataLoaderDelegate(::DraftSchematicLoader)

private class WeakDataLoaderDelegate<T: DataLoader>(loaderCreator: () -> T): DataLoaderDelegate<T>(::WeakReference, loaderCreator)
private class SoftDataLoaderDelegate<T: DataLoader>(loaderCreator: () -> T): DataLoaderDelegate<T>(::SoftReference, loaderCreator)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/***********************************************************************************
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
* Our goal is to create an emulator which will provide a server for players to *
* continue playing a game similar to the one they used to play. We are basing *
* it on the final publish of the game prior to end-game events. *
* *
* This file is part of Holocore. *
* *
* --------------------------------------------------------------------------------*
* *
* Holocore is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* Holocore is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.global.commands.callbacks

import com.projectswg.common.data.CRC
import com.projectswg.common.data.schematic.DraftSchematic
import com.projectswg.common.network.packets.swg.zone.object_controller.DraftSlotsQueryResponse
import com.projectswg.holocore.resources.support.data.server_info.loader.ServerData
import com.projectswg.holocore.resources.support.global.commands.ICmdCallback
import com.projectswg.holocore.resources.support.global.player.Player
import com.projectswg.holocore.resources.support.objects.swg.SWGObject

class RequestDraftSlotsCallback : ICmdCallback {
override fun execute(player: Player, target: SWGObject?, args: String) {
val crcs = args.trim().split(" ").map { it.toUInt() }
val clientCrc = crcs[0]
val serverCrc = crcs[1]
val schematic = draftSchematic(serverCrc) ?: return
val draftSlotsQueryResponse = DraftSlotsQueryResponse(schematic, player.creatureObject.objectId, clientCrc.toInt(), serverCrc.toInt())
player.sendPacket(draftSlotsQueryResponse)
}

private fun draftSchematic(serverCrc: UInt): DraftSchematic? {
val draftSchematicIff = CRC.getString(serverCrc.toInt())
return ServerData.draftSchematics.getDraftSchematic(draftSchematicIff)
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***********************************************************************************
* Copyright (c) 2018 /// Project SWG /// www.projectswg.com *
* Copyright (c) 2023 /// Project SWG /// www.projectswg.com *
* *
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
Expand All @@ -24,20 +24,24 @@
* You should have received a copy of the GNU Affero General Public License *
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
***********************************************************************************/
package com.projectswg.holocore.resources.support.global.commands.callbacks;
package com.projectswg.holocore.resources.support.global.commands.callbacks

import com.projectswg.common.data.schematic.DraftSchematic;
import com.projectswg.common.network.packets.swg.zone.object_controller.DraftSlotsQueryResponse;
import com.projectswg.holocore.resources.support.global.commands.ICmdCallback;
import com.projectswg.holocore.resources.support.global.player.Player;
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
import org.jetbrains.annotations.NotNull;
import com.projectswg.common.data.CRC
import com.projectswg.common.network.packets.swg.zone.resource.ResourceWeight
import com.projectswg.holocore.resources.support.global.commands.ICmdCallback
import com.projectswg.holocore.resources.support.global.player.Player
import com.projectswg.holocore.resources.support.objects.swg.SWGObject

public class RequestDraftSlotsCallback implements ICmdCallback{

@Override
public void execute(@NotNull Player player, SWGObject target, @NotNull String args) {
DraftSchematic schematic = new DraftSchematic();
player.sendPacket(new DraftSlotsQueryResponse(schematic));
class RequestResourceWeightsBatchCallback : ICmdCallback {
override fun execute(player: Player, target: SWGObject?, args: String) {
val clientCrc = args.trim().toInt()
val resourceWeight = ResourceWeight(player.creatureObject.objectId)
resourceWeight.attributes[0x00] = emptyList()
resourceWeight.resourceMaxWeights[0x00] = emptyList()
val serverCrc = 2027141215 // TODO don't hardcode slitherhorn CRCs
val combinedCrc = 8706505225174593761L
resourceWeight.schematicId = CRC.getCrc("object/draft_schematic/instrument/instrument_slitherhorn.iff")
resourceWeight.schematicCrc = CRC.getCrc("object/draft_schematic/instrument/instrument_slitherhorn.iff")
player.sendPacket(resourceWeight)
}
}
}
Loading
Loading